Goals

  1. Identify transcriptional patterns in AM associated with IAV, COVID-19, and common to both
  2. Determine source of IL6 and IL1B in the lung (if possible)

Setup

Load packages

library(ggplot2)
library(DESeq2)
library(pheatmap)
library(RColorBrewer)
library(viridis)
library(patchwork)
library(factoextra)
library(parallel)
library(uwot)
library(WGCNA)
library(ggsci)
library(topGO)
library(GO.db)
library(org.Hs.eg.db)
library(parallel)
library(doParallel)
library(biomaRt)
registerDoParallel(makeCluster(12))
register(MulticoreParam(12))
options(gsubfn.engine = "R")
set.seed(12345)
source("~/utils/R/pretty_MA_plot.R")
source("~/utils/R/k_means_figure.R")
source("~/utils/R/plotPCA_manual.R")
fig2_pal = pal_npg("nrc")(9)

sessionInfo()
R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux Server 7.5 (Maipo)

Matrix products: default
BLAS:   /hpc/software/lapack/3.6.0_gcc/lib64/libblas.so.3.6.0
LAPACK: /hpc/software/lapack/3.6.0_gcc/lib64/liblapack.so.3.6.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8   
 [6] LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] parallel  stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] RPushbullet_0.3.3           ggrepel_0.8.2               gtools_3.8.2                biomaRt_2.42.1              corrplot_0.84              
 [6] ggforce_0.3.2               googledrive_1.0.1           googlesheets4_0.2.0         spgs_1.0-3                  readxl_1.3.1               
[11] rtracklayer_1.46.0          forcats_0.5.0               stringr_1.4.0               dplyr_1.0.0                 purrr_0.3.4                
[16] readr_1.3.1                 tidyr_1.1.0                 tibble_3.0.1                tidyverse_1.3.0             doParallel_1.0.15          
[21] iterators_1.0.12            foreach_1.5.0               org.Hs.eg.db_3.10.0         topGO_2.38.1                SparseM_1.78               
[26] GO.db_3.10.0                AnnotationDbi_1.48.0        graph_1.64.0                ggsci_2.9                   WGCNA_1.69                 
[31] fastcluster_1.1.25          dynamicTreeCut_1.63-1       uwot_0.1.8                  Matrix_1.2-18               factoextra_1.0.7           
[36] patchwork_1.0.1             viridis_0.5.1               viridisLite_0.3.0           RColorBrewer_1.1-2          pheatmap_1.0.12            
[41] DESeq2_1.26.0               SummarizedExperiment_1.16.1 DelayedArray_0.12.3         BiocParallel_1.20.1         matrixStats_0.56.0         
[46] Biobase_2.48.0              GenomicRanges_1.38.0        GenomeInfoDb_1.22.1         IRanges_2.20.2              S4Vectors_0.24.4           
[51] BiocGenerics_0.34.0         ggplot2_3.3.2              

loaded via a namespace (and not attached):
  [1] backports_1.1.8          Hmisc_4.4-0              BiocFileCache_1.10.2     splines_3.6.3            digest_0.6.25           
  [6] htmltools_0.5.0          fansi_0.4.1              magrittr_1.5             checkmate_2.0.0          memoise_1.1.0           
 [11] cluster_2.1.0            Biostrings_2.54.0        annotate_1.64.0          modelr_0.1.8             askpass_1.1             
 [16] prettyunits_1.1.1        jpeg_0.1-8.1             colorspace_1.4-1         rappdirs_0.3.1           blob_1.2.1              
 [21] rvest_0.3.5              haven_2.3.1              xfun_0.15                crayon_1.3.4             RCurl_1.98-1.2          
 [26] jsonlite_1.7.0           genefilter_1.68.0        impute_1.60.0            survival_3.1-8           glue_1.4.1              
 [31] polyclip_1.10-0          gargle_0.5.0             gtable_0.3.0             zlibbioc_1.32.0          XVector_0.26.0          
 [36] scales_1.1.1             DBI_1.1.0                Rcpp_1.0.4.6             progress_1.2.2           xtable_1.8-4            
 [41] htmlTable_2.0.0          foreign_0.8-75           bit_1.1-15.2             preprocessCore_1.48.0    Formula_1.2-3           
 [46] htmlwidgets_1.5.1        httr_1.4.1               acepack_1.4.1            ellipsis_0.3.1           farver_2.0.3            
 [51] pkgconfig_2.0.3          XML_3.99-0.3             nnet_7.3-12              dbplyr_1.4.4             locfit_1.5-9.4          
 [56] labeling_0.3             tidyselect_1.1.0         rlang_0.4.6              munsell_0.5.0            cellranger_1.1.0        
 [61] tools_3.6.3              cli_2.0.2                generics_0.0.2           RSQLite_2.2.0            broom_0.5.6             
 [66] evaluate_0.14            yaml_2.2.1               knitr_1.29               bit64_0.9-7              fs_1.4.2                
 [71] nlme_3.1-144             xml2_1.3.2               compiler_3.6.3           rstudioapi_0.11          curl_4.3                
 [76] png_0.1-7                reprex_0.3.0             tweenr_1.0.1             geneplotter_1.64.0       stringi_1.4.6           
 [81] lattice_0.20-38          vctrs_0.3.1              pillar_1.4.4             lifecycle_0.2.0          data.table_1.12.8       
 [86] bitops_1.0-6             R6_2.4.1                 latticeExtra_0.6-29      gridExtra_2.3            codetools_0.2-16        
 [91] MASS_7.3-51.5            assertthat_0.2.1         openssl_1.4.2            withr_2.2.0              GenomicAlignments_1.22.1
 [96] Rsamtools_2.2.3          GenomeInfoDbData_1.2.2   hms_0.5.3                grid_3.6.3               rpart_4.1-15            
[101] rmarkdown_2.3            lubridate_1.7.9          base64enc_0.1-3         

Import data

mp = readRDS("/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_script_bulk_des_no_hURNA.rds")
mp$covid_confirmed = factor(mp$covid_confirmed)
mp$sex = factor(mp$gender)

#set up for comparison by diagnosis
mp$Diagnosis = gsub("-| ", "_", as.character(mp$pna_type))
mp$Diagnosis = factor(mp$Diagnosis, 
                      levels = c("Healthy_Control", "Non_Pneumonia_Control", "COVID_19", 
                                 "Other_Viral_Pneumonia", "Other_Pneumonia"))
mp$neutrophilic = mp$percent_neutrophils > 50
#for modeling, etc
mp$finite_day_of_intubation = mp$day_of_intubation
mp$finite_day_of_intubation[is.infinite(mp$finite_day_of_intubation)] = NA
mp$day0_sample = factor(mp$day_of_intubation >= 0 & mp$day_of_intubation <=2)
mp$day0_sample[is.na(mp$day0_sample)] = FALSE
design(mp) = as.formula("~ Diagnosis")
metadata = as.data.frame(colData(mp))

Summary stats

Number of samples overall

table(mp_des$covid_confirmed)

FALSE  TRUE 
  161    82 

Number of serial samples

n_samples = table(metadata$patient_id)
serial_patients = names(n_samples[n_samples > 1])
length(serial_patients)
[1] 41

Distribution of days

ggplot(metadata, aes(x = day_of_intubation)) +
  geom_histogram(fill = "dodgerblue4")

PCA

Calculate and organize

mp_vst = vst(mp, nsub = 3000, fitType = "local") #know from later that local is best
mp_counts = counts(estimateSizeFactors(mp), normalized = T)
pca_data = plotPCA_manual(mp_vst,
                          intgroup = c("covid_confirmed"),
                          pcs = 10)
pca_data$data = left_join(pca_data$data,
                     as.data.frame(colData(mp)),
                     by = c("name" = "sample", "covid_confirmed"))

#merge counts and pca data
gene_conv = as.data.frame(rowData(mp)) %>% 
  rownames_to_column(var = "ensembl_gene_id")
merge_counts = mp_counts %>% 
  t() %>%
  as.data.frame() %>% 
  rownames_to_column(var = "name")

#merge together for featureplot dataset
fp_data = left_join(pca_data$data, merge_counts, by = "name")
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 14 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 13 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 12 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 11 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 10 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 9 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 8 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 7 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 6 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 5 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 4 (<-localhost.localdomain:11950)
Warning in nm %in% out[seq_len(i - 1)] :
  closing unused connection 3 (<-localhost.localdomain:11950)

How many PCs?

#scree plot   
fviz_eig(pca_data$pca, 
         barfill = "dodgerblue4", 
         xlab = "Principal Component",
         ylab = "Percent Variance Explained", 
         main = "",
         ncp = 50,
         ggtheme = theme_bw(),
         addlabels = T) #4-5 PCs will do it

Examine loadings

loadings = pca_data$pca$rotation %>% 
  as.data.frame() %>% 
  rownames_to_column(var = "ensembl_gene_id") %>% 
  right_join(gene_conv, .)
Joining, by = "ensembl_gene_id"

PC1: MoAM Character

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = percent_total_CD206_high)) +
  geom_point(size = 3)

fabp4_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000170323))) +
  geom_point() +
  scale_color_viridis(name = "Log2(FABP4 Counts)")
spp1_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000118785))) +
  geom_point() +
  scale_color_viridis(name = "Log2(SPP1 Counts)")
fabp4_plot + spp1_plot

PC2: Patterns of activation (also by milieu)

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = C_Reactive_Protein)) +
  geom_point(size = 3)

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = LDH)) +
  geom_point(size = 3)

ggplot(fp_data, aes(x = PC1, y = PC2, shape = covid_confirmed, color = FERRITIN)) +
  geom_point(size = 3)

inhba_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000122641))) +
  geom_point() +
  scale_color_viridis(name = "Log2(INHBA)")
il1b_plot = ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(ENSG00000125538))) +
  geom_point() +
  scale_color_viridis(name = "Log2(IL1b)")

After adding healthy controls this is longer true.

PC3: Male/female?

ggplot(fp_data, aes(x = PC2, y = PC3, color = gender)) +
  geom_point(size = 3)

xist_plot = ggplot(fp_data, aes(x = PC2, y = PC3, color = log2(ENSG00000229807))) +
  geom_point() +
  scale_color_viridis(name = "Log2(XIST)")

Not really

Condition

ggplot(fp_data, aes(x = PC1, y = PC2, color = Diagnosis)) +
  geom_point(size = 2) +
  stat_ellipse()

Day of intubation

ggplot(fp_data, aes(x = PC1, y = PC2, color = log2(day_of_intubation))) +
  geom_point(size = 3)

No clear separation.

Determine best dispersion estimates

Parametric

#note: DESeq is refitting far too many genes. Need to turn this off.
mp_des_parametric = DESeq(mp, 
                          fitType = "parametric",
                          parallel = T,
                          minReplicatesForReplace = Inf)
estimating size factors
estimating dispersions
gene-wise dispersion estimates: 12 workers
mean-dispersion relationship
final dispersion estimates, fitting model and testing: 12 workers
plotDispEsts(mp_des_parametric, cex = 0.1)

This fit really isn’t bad, but overestimates at lower expression (probably not a huge deal).

Local

mp_des_local = DESeq(mp,
                     fitType = "local",
                     parallel = T,
                     minReplicatesForReplace=Inf)
estimating size factors
estimating dispersions
gene-wise dispersion estimates: 12 workers
mean-dispersion relationship
final dispersion estimates, fitting model and testing: 12 workers
plotDispEsts(mp_des_local, cex = 0.1)


mp_des = mp_des_local
rm(mp_des_local, mp_des_parametric)

Still not perfect, but a lot better.

#used a few times later; safest to put here
#identify infected samples
non_human_genes = subset(gene_conv, !(grepl("^ENSG", ensembl_gene_id))) #human genes all have this prefix
non_human_genes$gene_name[non_human_genes$ensembl_gene_id == "gene-UJ99_s6gp1"] = "NA" #neuraminidase was misread
non_human_genes$virus = factor(ifelse(grepl("UJ99", non_human_genes$ensembl_gene_id),
                               yes = "Influenza A/California/07/2009",
                               no = "SARS-CoV-2"))
cov2_genes = subset(non_human_genes, grepl("SARS|GU280", ensembl_gene_id))
iav_genes = subset(non_human_genes, grepl("UJ99", ensembl_gene_id))
flu_counts = counts(mp_des, normalized = T)[iav_genes$ensembl_gene_id, ]
flu_detected = colnames(flu_counts[, colSums(flu_counts) > 0])
cov2_counts = counts(mp_des, normalized = T)[cov2_genes$ensembl_gene_id, ]
cov2_detected = colnames(cov2_counts[, colSums(cov2_counts) > 0])
mp_des$sars_cov2_detected = factor(mp_des$sample %in% cov2_detected)
mp_des$iav_h1n1_detected = factor(mp_des$sample %in% flu_detected)

## Replicating CoV2 samples
### overall
antisense_counts = cov2_counts["SARS_CoV_2_antisense_genome", ]
sense_counts = cov2_counts[2:nrow(cov2_counts), ]
replicating_cov2 = intersect(names(antisense_counts)[antisense_counts > 0],
                             colnames(sense_counts[, colSums(sense_counts) > 0]))
### just covid
percent_detected_covid = length(unique(subset(metadata, sample %in% cov2_detected & covid_confirmed == TRUE)$study_id)) / length(unique(subset(metadata, covid_confirmed == TRUE)$study_id)) * 100
percent_detected_covid
[1] 66.66667
percent_replicating_covid = length(unique(subset(metadata, sample %in% replicating_cov2 & covid_confirmed == TRUE)$study_id)) / length(unique(subset(metadata, covid_confirmed == TRUE)$study_id)) * 100
percent_replicating_covid
[1] 25.4902
percent_replicating_covid / percent_detected_covid * 100
[1] 38.23529

Sanity checks

SARS-CoV-2

Does expression of viral genes correlate with covid diagnosis?

cov2_counts = lapply(cov2_genes$ensembl_gene_id, function(x){
  counts = plotCounts(mp,
                      gene = x,
                      intgroup = "Diagnosis",
                      returnData = T, 
                      pc = T)
  counts$gene = x
  return(counts)})
cov2_counts = bind_rows(cov2_counts)

ggplot(cov2_counts, aes(x = Diagnosis, y = count, fill = gene)) +
  geom_boxplot() +
  scale_y_log10()

Now that we have all of the necessary metadata, this looks fantastic.

Do counts cluster by virus and diagnosis?

viral_counts = counts(mp_des, normalized = T) 
viral_counts = viral_counts[non_human_genes$ensembl_gene_id, ]
viral_counts = log10(viral_counts + 0.5)

virus_detection = vector(mode = "character", length = ncol(mp_des))
for(i in 1:ncol(mp_des))
{
  has_covid = mp_des$covid_confirmed[i] == TRUE
  has_iav_h1n1 = mp_des$INFLUENZA_A_H1_2009[i] == "Positive"
  has_other_coronavirus = mp_des$any_coronavirus_non_covid[i] == TRUE
  #recode NA as FALSE for safety
  if(is.na(has_iav_h1n1)) 
  {
    has_iav_h1n1 = FALSE
  }
  if(is.na(has_other_coronavirus)) 
  {
    has_other_coronavirus = FALSE
  }
  
  if(has_covid == TRUE && has_iav_h1n1 == TRUE && has_other_coronavirus == TRUE)
  {
    virus_detection[i] = "SARS-CoV-2 & Other Coronavirus & Influenza A/California/07/2009"
  } else if(has_covid == TRUE && has_iav_h1n1 == FALSE && has_other_coronavirus == FALSE)
  {
    virus_detection[i] = "SARS-CoV-2"
  } else if(has_covid == FALSE && has_iav_h1n1 == TRUE && has_other_coronavirus == FALSE)
  {
    virus_detection[i] = "Influenza A/California/07/2009"
  } else if(has_covid == FALSE && has_iav_h1n1 == FALSE && has_other_coronavirus == TRUE)
  {
     virus_detection[i] = "Other Coronavirus"
  } else if(has_covid == TRUE && has_iav_h1n1 == TRUE && has_other_coronavirus == FALSE)
  {
    virus_detection[i] = "SARS-CoV-2 & Influenza A/California/07/2009"
  } else if(has_covid == TRUE && has_iav_h1n1 == FALSE && has_other_coronavirus == TRUE)
  {
    virus_detection[i] = "SARS-CoV-2 & Other Coronavirus"
  } else if(has_covid == FALSE && has_iav_h1n1 == TRUE && has_other_coronavirus == TRUE)
  {
    virus_detection[i] = "Other Coronavirus & Influenza A/California/07/2009"
  } else
  {
    virus_detection[i] = NA
  }
}
mp_des$detected_viruses = factor(virus_detection)
  
diagnosis_annotation = as.data.frame(colData(mp_des)) %>% 
  dplyr::select(Diagnosis = detected_viruses)
gene_annotation = non_human_genes %>% 
  remove_rownames() %>% 
  column_to_rownames("ensembl_gene_id") %>% 
  dplyr::select(`Viral Origin` = virus)
gene_names = non_human_genes$gene_name
gene_names[gene_names == "SARS_CoV_2_antisense_genome"] = "Antisense"

viral_expression_heatmap = pheatmap(viral_counts,
        clustering_method = "ward.D2",
        show_colnames = F,
        color = inferno(100),
        annotation_col = diagnosis_annotation,
        annotation_row = gene_annotation,
        labels_row = gene_names,
        annotation_colors = list(Diagnosis = c("SARS-CoV-2" = fig2_pal[1], "Other Coronavirus" = fig2_pal[2],
                                                "Influenza A/California/07/2009" = fig2_pal[3], "Other Coronavirus & Influenza A/California/07/2009" = fig2_pal[4]),
                                  `Viral Origin` = c("SARS-CoV-2" = fig2_pal[1], "Influenza A/California/07/2009" = fig2_pal[3])),
        angle_col = 45, 
        annotation_names_row = F)

Patient 1174

This patient apparently met criteria for COVID well before the first known cases in Chicago

cov2_counts = counts(mp_des, normalized = T)[cov2_genes$ensembl_gene_id, ]
samples_1174 = mp_des$study_id == "1174"
samples_1174[is.na(samples_1174)] = FALSE
tubes_1174 = mp_des$sample[samples_1174]
cov2_counts_1174 = cov2_counts[, tubes_1174]
cov2_counts_1174
SARS_CoV_2_antisense_genome             gene-GU280_gp01             gene-GU280_gp02             gene-GU280_gp03             gene-GU280_gp04 
                          0                           0                           0                           0                           0 
            gene-GU280_gp05             gene-GU280_gp06             gene-GU280_gp07             gene-GU280_gp08             gene-GU280_gp09 
                          0                           0                           0                           0                           0 
            gene-GU280_gp10             gene-GU280_gp11 
                          0                           0 

No detection, at least in macrophages.

Do CoV2 reads decrease over time?

Checking for viral clearance

covid_cases = mp_des[, mp_des$covid_confirmed == TRUE]
covid_counts = counts(covid_cases, normalized = T)
covid_counts = covid_counts[cov2_genes$ensembl_gene_id, ]

covid_counts = covid_counts %>% 
  as.data.frame() %>% 
  rownames_to_column(var = "gene") %>% 
  pivot_longer(cols = "340195046":"340239867",
               names_to = "sample",
               values_to = "Counts") %>% 
  left_join(., non_human_genes, by = c("gene" = "ensembl_gene_id")) %>% 
  dplyr::select(-c(gene, virus)) %>% 
  left_join(., as.data.frame(colData(mp_des)), by = "sample")

ggplot(covid_counts, aes(x = day_of_intubation, y = Counts)) +
  facet_wrap(~ gene_name, scales = "free_y") +
  geom_point() +
  geom_smooth(se = F)

Unfortunately this is somewhat binarized. Better to treat it as such.

covid_counts_binarized = covid_counts %>% 
  group_by(sample) %>% 
  mutate(all_viral_counts = sum(Counts)) %>% 
  dplyr::select(sample, all_viral_counts, day_of_intubation) %>% 
  unique() %>% 
  mutate(virus_detected = all_viral_counts > 0)

cor.test(covid_counts_binarized$all_viral_counts, covid_counts_binarized$day_of_intubation, method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  covid_counts_binarized$all_viral_counts and covid_counts_binarized$day_of_intubation
S = 35853, p-value = 0.0008307
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
-0.445437 
ggplot(covid_counts_binarized, aes(x = day_of_intubation, y = all_viral_counts)) +
  geom_point() +
  scale_y_continuous(trans = "log2") +
  geom_smooth(se = F)

Export for modeling core

col_types = unlist(lapply(metadata, class))
list_cols = names(col_types[col_types == "AsIs"])
safe_metadata = metadata %>% 
  dplyr::select(-c(all_of(list_cols))) %>% 
  as.data.frame()
write.csv(safe_metadata, "/projects/b1038/Pulmonary/Workspace/COVID19_bal_ms/200709_bulk_metadata.csv")
write.csv(counts(mp_des, normalized = F), "/projects/b1038/Pulmonary/Workspace/COVID19_bal_ms/200709_bulk_counts_raw.csv")
write.csv(counts(mp_des, normalized = T), "/projects/b1038/Pulmonary/Workspace/COVID19_bal_ms/200709_bulk_counts_deseq2_normalized.csv")

Which samples are worth sequencing further?

First batch

good_samples = mp_des[, ((!is.na(mp_des$RIN) & mp_des$RIN >= 7) & 
                    mp_des$STAR_mqc_generalstats_star_uniquely_mapped_percent >= 30 &
                    mp_des$featureCounts_mqc_generalstats_featurecounts_percent_assigned >= 30) &
                    mp_des$RNA_concentration_pg_ul >= 125 |
                    (mp_des$iav_h1n1_detected == TRUE | mp_des$sars_cov2_detected == TRUE)]

selection_data = as.data.frame(colData(good_samples)) %>% 
  dplyr::select(sample, tc_pt_study_id, RIN, STAR_mqc_generalstats_star_uniquely_mapped_percent,
         featureCounts_mqc_generalstats_featurecounts_percent_assigned, iav_h1n1_detected, 
         sars_cov2_detected, covid_confirmed, batch, RNA_concentration_pg_ul, pna_type)
selection_data

Keepers:
- 340224808 (IAV) - 304017553 (IAV + likely another coronavirus) - 340239805 (Cov2) - 340233896 (Cov2) - 340239790 (Cov2) - 340239789 (Cov2) - 304012699 (Other – likely another coronavirus) - 300312389 (other) - 304020362 (other)

keepers = selection_data %>% 
  dplyr::filter(sample %in% c(304020298, 340224808, 304017553, 340239805, 340233896,
                              340239790, 340239789, 304012699, 300312389, 304020362)) %>% 
  mutate(vol_for_250_pg = round(250 / RNA_concentration_pg_ul, digits = 3))
keepers$dilution = ifelse(keepers$vol_for_250_pg > 0.5,
                          yes = 1,
                          no = ifelse(keepers$vol_for_250_pg > 0.1,
                                      yes = 5,
                                      no = 20))
keepers$dilution_vol_for_250_pg = round(250 / (keepers$RNA_concentration_pg_ul / keepers$dilution), digits = 3)
write.csv(keepers, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200612_resequencing_samples.csv")
keepers

Signatures associated with SARS-CoV-2

Single genes

IL6

il6_counts = plotCounts(mp_des, 
           gene = "ENSG00000136244",
           normalized = T,
           intgroup = "covid_confirmed",
           returnData = T) %>% 
  rownames_to_column(var = "sample") %>% 
  left_join(., 
            metadata,
            by = c("sample", "covid_confirmed"))

cor.test(il6_counts$count, il6_counts$percent_total_CD206_high)

    Pearson's product-moment correlation

data:  il6_counts$count and il6_counts$percent_total_CD206_high
t = -1.967, df = 214, p-value = 0.05047
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.2620931112  0.0002344531
sample estimates:
       cor 
-0.1332627 
il6_plot = ggplot(il6_counts, aes(x = percent_total_CD206_high, y = count, color = covid_confirmed)) +
  geom_point(size = 3) +
  scale_y_log10() +
  ylab("IL6 Counts")

Later confirmed NSD by group. Clearly correlates with MoAM character.

IL1b

il1b_counts = plotCounts(mp_des, 
           gene = "ENSG00000125538",
           normalized = T,
           intgroup = "covid_confirmed",
           returnData = T) %>% 
  rownames_to_column(var = "sample") %>% 
  left_join(., 
            metadata,
            by = c("sample", "covid_confirmed"))

cor.test(il1b_counts$count, il1b_counts$percent_total_CD206_high)

    Pearson's product-moment correlation

data:  il1b_counts$count and il1b_counts$percent_total_CD206_high
t = -3.8972, df = 214, p-value = 0.0001302
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.3779331 -0.1283454
sample estimates:
       cor 
-0.2574278 
il1b_plot = ggplot(il1b_counts, aes(x = percent_total_CD206_high, y = count, color = covid_confirmed)) +
  geom_point(size = 3) +
  scale_y_log10() + 
  ylab("IL1b Counts")

il6_plot / il1b_plot

Later confirmed significantly downregulated, actually.

Basic DEA

Gene hits

Versus healthy controls

cov2_vs_hc_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Healthy_Control"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_hc_results_ids = cov2_vs_hc_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
write.csv(cov2_vs_hc_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_healthycontrols.csv")

cov2_vs_hc_results_ids

Upregulation of CoV-2 genes is gorgeous

Versus non-pna (sick) controls

cov2_vs_npc_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Non_Pneumonia_Control"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_npc_results_ids = cov2_vs_npc_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
write.csv(cov2_vs_npc_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_nonpneumoniacontrols.csv")

cov2_vs_npc_results_ids

Versus other viral PNA

cov2_vs_ovp_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Other_Viral_Pneumonia"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_ovp_results_ids = cov2_vs_ovp_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
cov2_vs_ovp_results_ids

write.csv(cov2_vs_ovp_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_otherviralpneumonia.csv")

Versus other PNA

cov2_vs_other_pna_results = as.data.frame(results(object = mp_des,
                                  contrast = c("Diagnosis", "COVID_19", "Other_Pneumonia"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_other_pna_results_ids = cov2_vs_other_pna_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id)) %>% 
  arrange(log2FoldChange)
Joining, by = "ensembl_gene_id"
write.csv(cov2_vs_other_pna_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200717_standard_DEA_covid_over_otherpneumonia.csv")

cov2_vs_other_pna_results_ids

MA Plot

pretty_MA_plot(cov2_vs_ovp_results, custom_annotation =  gene_conv)

Heatmap

How many clusters does it take?

elbow = k_elbow(dge = mp_des, design = "~Diagnosis", 
        cores = 12, 
        minReps = Inf,
        random_seed = 12345,
        max_k = 25,
        qval_cutoff = 0.01)
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates: 12 workers
mean-dispersion relationship
final dispersion estimates, fitting model and testing: 12 workers

5 seems fair.

cov2_kmeans_noclustering = k_means_figure(dge = mp_des,
                                 design = "~Diagnosis",
                                 k = 5,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("Diagnosis", "finite_day_of_intubation"),
                                 breaks = seq(-2, 2, length.out=101),
                                 cores = 12,
                             minReps = Inf,
                             return_genes = T,
                             display_go_terms = F,
                             return_go_terms = T,
                             cluster_columns = F,
                             show_rownames = F,
                             baseMeanCutoff = 20,
                             random_seed = 12345,
                             qval_cutoff = 0.05,
                             annotation_colors = list(Diagnosis = c("Healthy_Control" = fig2_pal[6],
                                                                    "Non_Pneumonia_Control" = fig2_pal[2],
                                                                    "COVID_19" = fig2_pal[1], 
                                                                    "Other_Viral_Pneumonia" = fig2_pal[3],
                                                                    "Other_Pneumonia" = fig2_pal[4]),
                                                      finite_day_of_intubation =  intubation_pal), 
                             custom_order = c(3, 5, 1, 2, 4), 
                             sortColumns = T,
                             column_sort_factors = c("Diagnosis", "day0_sample"))
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates: 12 workers
mean-dispersion relationship
final dispersion estimates, fitting model and testing: 12 workers
Joining, by = "cluster"

Building most specific GOs .....

Building most specific GOs .....

Building most specific GOs .....

Building most specific GOs .....

Building most specific GOs .....
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 16096 GO terms and 38209 relations. )
    ( 16096 GO terms and 38209 relations. )
    ( 16096 GO terms and 38209 relations. )
    ( 16096 GO terms and 38209 relations. )
    ( 16096 GO terms and 38209 relations. )

Annotating nodes ...............

Annotating nodes ...............

Annotating nodes ...............

Annotating nodes ...............

Annotating nodes ...............
    ( 16536 genes annotated to the GO terms. )
    ( 16536 genes annotated to the GO terms. )
    ( 16536 genes annotated to the GO terms. )
    ( 16536 genes annotated to the GO terms. )
    ( 16536 genes annotated to the GO terms. )

             -- Classic Algorithm -- 

         the algorithm is scoring 5134 nontrivial nodes
         parameters: 
             test statistic: Fisher test

             -- Classic Algorithm -- 

         the algorithm is scoring 5533 nontrivial nodes
         parameters: 
             test statistic: Fisher test

             -- Classic Algorithm -- 

         the algorithm is scoring 5127 nontrivial nodes
         parameters: 
             test statistic: Fisher test

             -- Classic Algorithm -- 

         the algorithm is scoring 5513 nontrivial nodes
         parameters: 
             test statistic: Fisher test

             -- Classic Algorithm -- 

         the algorithm is scoring 6447 nontrivial nodes
         parameters: 
             test statistic: Fisher test

This is actually very cool (and nicely foreshadows the later WGCNA results). C1: mostly COVID-related(!); highly enriched for type I interferon response (not production so much), as well as MHC-I. C2: mostly nonviral pneumonias. Pretty classic STAT3 inflammatory response.

D0 Heatmap

d0_des = mp_des[, !is.na(mp_des$day_of_intubation) & mp_des$day_of_intubation <= 2 & mp_des$day_of_intubation >= 0]
# cov2_d0_kmeans_noclustering = k_means_figure(dge = d0_des, 
#                                  design = "~Diagnosis",
#                                  k = 3,
#                                  go_annotations = "org.Hs.eg.db",
#                                  ensembl_db = "hsapiens_gene_ensembl",
#                                  legend_factors = c("Diagnosis", "percent_total_CD206_high"),
#                                  breaks = seq(-3, 3, length.out=101),
#                                  cores = 12,
#                              minReps = Inf,
#                              return_genes = T,
#                              display_go_terms = F,
#                              return_go_terms = T,
#                              cluster_columns = F,
#                              label_fontsize = 2,
#                              customAnno = gene_conv,
#                              annoJoinCol = "ensembl_gene_id",
#                              sortColumns = T,
#                              colSortFactor = "Diagnosis",
#                              baseMeanCutoff = 20)

cov2_d0_kmeans_clustered = k_means_figure(dge = d0_des, 
                                 design = "~Diagnosis",
                                 k = 3,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("Diagnosis", "percent_total_CD206_high"),
                                 breaks = seq(-3, 3, length.out=101),
                                 cores = 12,
                             minReps = Inf,
                             return_genes = T,
                             display_go_terms = F,
                             return_go_terms = T,
                             cluster_columns = T,
                             label_fontsize = 2,
                             customAnno = gene_conv,
                             annoJoinCol = "ensembl_gene_id",
                             baseMeanCutoff = 20)

Individual genes

CCL24

This was an interesting COVID-specific hit. According to published data, it is a highly selective chemoattractant for T cells. Would expect that it should correlate with T cell abundance.

ccl24_counts = plotCounts(mp_des, 
                          gene = "ENSG00000106178",
                          intgroup = "Diagnosis",
                       normalized = T,
                       pc = T,
                       returnData = T)
ggplot(ccl24_counts, aes(x = Diagnosis, y = count, fill  = Diagnosis)) +
  geom_boxplot(width = 0.5, outlier.shape = NA) +
  geom_jitter(size = 0.1, width = 0.25) +
  scale_y_continuous(trans = "log10") +
  scale_fill_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non_Pneumonia_Control" = fig2_pal[2],
                               "COVID_19" = fig2_pal[1],
                               "Other_Viral_Pneumonia" = fig2_pal[3],
                               "Other_Pneumonia" = fig2_pal[4])) +
  scale_x_discrete(labels = c("Healthy_Control" = "Healthy\nControl",
                               "Non_Pneumonia_Control" = "Non-Pneumonia\nControl",
                               "COVID_19" = "COVID-19",
                               "Other_Viral_Pneumonia" = "Other Viral\nPneumonia",
                               "Other_Pneumonia" = "Other\nPneumonia")) +
  xlab("") +
  ylab("CCL24 Counts") +
  theme_bw() +
  theme(legend.position = "none", 
        text = element_text(size = 32, family = "Arial"),
        plot.title = element_text(hjust = 0.5))

Pretty poor correlation

IL-6

Sasha’s picks

All to start

Compare with sort data

Subset to samples with sorting data

Determine best dispersion estimates

Parametric

Actually very decent

Local

Both have their issues but this at least does not throw out low-expression genes for having infinite dispersion.

PCA

Clustering

All samples

Day 0

DEA

Versus controls

cov2_vs_npc_results = as.data.frame(results(object = sorted_des,
                                  contrast = c("Diagnosis", "COVID_19", "Non_Pneumonia_Control"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_npc_results_ids = cov2_vs_npc_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id))

write.csv(cov2_vs_npc_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200702_sorted_DEA_covid_over_nonpneumoniacontrols.csv")

cov2_vs_npc_results_ids

Versus other viral PNA

cov2_vs_ovp_results = as.data.frame(results(object = sorted_des,
                                  contrast = c("Diagnosis", "COVID_19", "Other_Viral_Pneumonia"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_ovp_results_ids = cov2_vs_ovp_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id))

write.csv(cov2_vs_ovp_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200702_sorted_DEA_covid_over_otherviralpneumonia.csv")

cov2_vs_npc_results_ids
cov2_vs_other_pna_results = as.data.frame(results(object = sorted_des,
                                  contrast = c("Diagnosis", "COVID_19", "Other_Pneumonia"),
                                  alpha = 0.05,
                                  parallel = T))

cov2_vs_other_pna_results_ids = cov2_vs_other_pna_results %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id))

write.csv(cov2_vs_other_pna_results_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200702_sorted_DEA_covid_over_otherpneumonia.csv")

cov2_vs_other_pna_results_ids

Unsurprisingly, there are very few valid differences here

MoAM percentage

MoAM_results_sorted = results(sorted_des, 
                               name = c("percent_total_CD206_high")) %>% 
  as.data.frame()

MoAM_results_sorted_ids = MoAM_results_sorted %>% 
  rownames_to_column("ensembl_gene_id") %>% 
  left_join(., gene_conv) %>% 
  dplyr::filter(padj < 0.05 | !grepl("ENSG", ensembl_gene_id))

write.csv(MoAM_results_sorted_ids, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200702_sorted_DEA_percent_CD206_high.csv")

MoAM_results_sorted_ids
pretty_MA_plot(MoAM_results_sorted, mart_name = "hsapiens_gene_ensembl")

This looks quite resasuring. CD206 hi samples have elevated expression of FABP4, anticorrelates with SPP1, CXCL8.

What can be explained by MoAM% alone?

TMPRSS2

d = plotCounts(sorted_des, 
               gene = "ENSG00000184012",
               intgroup = "percent_total_CD206_high",
               normalized = T,
               returnData = T)
ggplot(d, aes(x = percent_total_CD206_high, y = count)) +
  geom_point() +
  ylab("MRC1 (CD206) Counts")

Comparing different pathogens

Individual pathogens

pathogen_set = mp_des[, !is.na(mp$pathogen)]
pathogen_set$pathogen = factor(as.character(pathogen_set$pathogen)) #refactor
pathogen_kmeans = k_means_figure(dge = pathogen_set, 
                                 design = "~pathogen",
                                 k = 6,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("pathogen", "covid_confirmed"),
                                 breaks = seq(-3, 3, length.out=101),
                                 cores = 12)

Probably too granular

Broad groupings

infection_type_kmeans = k_means_figure(dge = pathogen_set, 
                                 design = "~infection_type",
                                 k = 4,
                                 go_annotations = "org.Hs.eg.db",
                                 ensembl_db = "hsapiens_gene_ensembl",
                                 legend_factors = c("pathogen", "infection_type"),
                                 breaks = seq(-3, 3, length.out=101),
                                 cores = 12)

Random

ACE2 counts

ace2_counts = plotCounts(mp_des, 
                         gene = "ENSG00000130234", 
                         intgroup = "covid_confirmed",
                         returnData = T,
                         normalized = T, 
                         pc = F)
ggplot(ace2_counts, aes(x = count)) +
  geom_histogram(fill = "dodgerblue4", ) +
  ylab("Number of Samples") +
  xlab("ACE2 Count")

Trajectories?

All samples

We will use PCA as is recommended to make computation feasible.

Patients actually separate out really well here. This might be worth including as a supplement. With that said, probably better to just use COVID patients for “trajectories”. It looks like there may be some structure to the COVID data.

Only COVID

#remove non-detected genes
#note that PCA should only use genes detected in all samples (3081)
COVID_counts = t(counts(mp_des[, mp_des$Diagnosis == "COVID_19"], normalized = T)) #need size normalization
prop_detected = apply(X = COVID_counts, MARGIN = 2, FUN = detection_rate)
COVID_counts = COVID_counts[, prop_detected > 0.1]
mean_detection = colMeans(COVID_counts)
COVID_counts = COVID_counts[, mean_detection >= 5]

COVID_pca = prcomp(COVID_counts)
fviz_eig(COVID_pca, 
         barfill = "dodgerblue4", 
         xlab = "Principal Component",
         ylab = "Percent Variance Explained", 
         main = "",
         ncp = 50,
         ggtheme = theme_bw(),
         addlabels = T) #20 should capture almost everything


COVID_umap = umap(X = COVID_counts, 
                  pca = 20, 
                  pca_center = T, 
                  n_threads = 1, 
                  scale = "Z", 
                  min_dist = 0.4)
rownames(COVID_umap) = rownames(COVID_counts)
colnames(COVID_umap) = c("UMAP_1", "UMAP_2")
COVID_umap = as.data.frame(COVID_umap)
COVID_umap$sample = rownames(COVID_umap)
COVID_umap = left_join(COVID_umap, metadata, by = "sample") %>% 
  arrange(study_id, day_of_intubation) # so we can draw paths

ggplot(COVID_umap, aes(x = UMAP_1, y = UMAP_2, color = day_of_intubation)) +
  scale_color_viridis() +
  geom_point()

ggplot(COVID_umap, aes(x = UMAP_1, y = UMAP_2, shape = study_id, color = day_of_intubation)) +
  scale_color_viridis() +
  geom_path(arrow = grid::arrow())

Not so much structure it seems.

WGCNA

What gene modules are associated with covid? Which change substantially over time on ventilator?
## Thesholding

#setup
enableWGCNAThreads(nThreads = 12)
Allowing parallel execution with up to 12 working processes.
WGCNAnThreads()
[1] 12
# Choose a set of soft-thresholding powers
powers = c(1:20)

# Call the network topology analysis functions
sft = pickSoftThreshold(all_counts, powerVector = powers, verbose = 5, networkType = "signed")
Warning: closing unused connection 14 (<-localhost.localdomain:11063)
Warning: closing unused connection 13 (<-localhost.localdomain:11063)
Warning: closing unused connection 12 (<-localhost.localdomain:11063)
Warning: closing unused connection 11 (<-localhost.localdomain:11063)
Warning: closing unused connection 10 (<-localhost.localdomain:11063)
Warning: closing unused connection 9 (<-localhost.localdomain:11063)
Warning: closing unused connection 8 (<-localhost.localdomain:11063)
Warning: closing unused connection 7 (<-localhost.localdomain:11063)
Warning: closing unused connection 6 (<-localhost.localdomain:11063)
Warning: closing unused connection 5 (<-localhost.localdomain:11063)
Warning: closing unused connection 4 (<-localhost.localdomain:11063)
Warning: closing unused connection 3 (<-localhost.localdomain:11063)
pickSoftThreshold: will use block size 3395.
 pickSoftThreshold: calculating connectivity for given powers...
   ..working on genes 1 through 3395 of 13176
   ..working on genes 3396 through 6790 of 13176
   ..working on genes 6791 through 10185 of 13176
   ..working on genes 10186 through 13176 of 13176
# Plot the results:
sizeGrWindow(9, 5)
par(mfrow = c(1,2))
cex1 = 0.9

# Scale-free topology fit index as a function of the soft-thresholding power
plot(sft$fitIndices[,1], 
     -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
     xlab="Soft Threshold (power)",
     ylab="Scale Free Topology Model Fit,signed R^2",
     type="n",
     main = paste("Scale independence"))
text(sft$fitIndices[,1], 
     -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
     labels=powers,
     cex=cex1,
     col="red")

# this line corresponds to using an R^2 cut-off of h
abline(h=0.90,col="red")

# Mean connectivity as a function of the soft-thresholding power
plot(sft$fitIndices[,1], 
     sft$fitIndices[,5],
     xlab="Soft Threshold (power)",
     ylab="Mean Connectivity", 
     type="n",
     main = paste("Mean connectivity"))
text(sft$fitIndices[,1], sft$fitIndices[,5], labels=powers, cex=cex1,col="red")

7 looks like the intersection after adding healthy controls

Co-expression by similarity and adjacency

softPower = 7
adjacency = adjacency(all_counts, power = softPower, type = "signed")

Topological overlap matrix

# Turn adjacency into topological overlap
TOM = TOMsimilarity(adjacency, TOMType = "signed")
..connectivity..
..matrix multiplication (system BLAS)..
..normalization..
..done.
pbPost()
dissTOM = 1-TOM

Cluster by TOM distance

geneTree = hclust(as.dist(dissTOM), method = "average")

sizeGrWindow(12,9)
plot(geneTree, 
     xlab="", 
     sub="", 
     main = "Gene clustering on TOM-based dissimilarity",
     labels = FALSE, 
     hang = 0.04)

Create modules

minModuleSize = 30 # may need to adjust

# Make modules based on clusters
dynamicMods = cutreeDynamic(dendro = geneTree, 
                            distM = dissTOM,
                            deepSplit = 2,
                            pamRespectsDendro = FALSE,
                            minClusterSize = minModuleSize)
 ..cutHeight not given, setting it to 0.989  ===>  99% of the (truncated) height range in dendro.
 ..done.
table(dynamicMods)
dynamicMods
   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
2734 2473 2350 1019  830  711  697  647  370  293  273  271  246  143  119 

Label modules (yeah this is dumb – rename later)

# Convert numeric labels into colors
dynamicColors = labels2colors(dynamicMods)
table(dynamicColors)
dynamicColors
       black         blue        brown         cyan        green  greenyellow      magenta midnightblue         pink       purple          red       salmon          tan 
         697         2473         2350          143          830          273          370          119          647          293          711          246          271 
   turquoise       yellow 
        2734         1019 
# Plot the dendrogram and colors underneath
sizeGrWindow(8,6)
plotDendroAndColors(geneTree, 
                    dynamicColors, 
                    "Dynamic Tree Cut",
                    dendroLabels = FALSE,
                    hang = 0.03,
                    addGuide = TRUE,
                    guideHang = 0.05,
                    main = "Gene dendrogram and module colors")

Looks like we captured the structure pretty well.

Merge similar modules

# Calculate eigengenes
MEList = moduleEigengenes(all_counts, 
                          colors = dynamicColors)
MEs = MEList$eigengenes

# Calculate dissimilarity of module eigengenes
MEDiss = 1-cor(MEs)

# Cluster module eigengenes
METree = hclust(as.dist(MEDiss), 
                method = "average")

# Plot the result
sizeGrWindow(7, 6)
plot(METree, 
     main = "Clustering of module eigengenes",
     xlab = "",
     sub = "")

#Now cut at height of 0.5 to get correlation of 0.5  
#standard is 0.25, but we have some really similar modules that are not relevant
MEDissThres = 0.25

# Plot the cut line into the dendrogram
abline(h=MEDissThres, 
       col = "red")

# Call an automatic merging function
merge = mergeCloseModules(all_counts, 
                          dynamicColors, 
                          cutHeight = MEDissThres, 
                          verbose = 3)
 mergeCloseModules: Merging modules whose distance is less than 0.25
   multiSetMEs: Calculating module MEs.
     Working on set 1 ...
     moduleEigengenes: Calculating 15 module eigengenes in given set.
   Calculating new MEs...
   multiSetMEs: Calculating module MEs.
     Working on set 1 ...
     moduleEigengenes: Calculating 15 module eigengenes in given set.
# The merged module colors
mergedColors = merge$colors

# Eigengenes of the new merged modules:
mergedMEs = merge$newMEs

# Rename to moduleColors
moduleColors = mergedColors

# Construct numerical labels corresponding to the colors
colorOrder = c("grey", standardColors(50))
moduleLabels = match(moduleColors, colorOrder)-1
MEs = mergedMEs

#replot
sizeGrWindow(12, 9)
plotDendroAndColors(geneTree, 
                    cbind(dynamicColors, mergedColors),
                    c("Dynamic Tree Cut", "Merged dynamic"),
                    dendroLabels = FALSE, 
                    hang = 0.03,
                    addGuide = TRUE, 
                    guideHang = 0.05)

No change

Relate back to traits

Without vent settings

1
[1] 1
# Define numbers of genes and samples
nGenes = ncol(all_counts)
nSamples = nrow(all_counts)
metadata = as.data.frame(colData(mp_des))
md_of_interest = metadata %>% 
  mutate(deceased = ifelse(binned_outcome == "Deceased",
                           yes = 1,
                           no = 0)) %>% 
  mutate(has_covid = ifelse(covid_confirmed == "TRUE",
                           yes = 1,
                           no = 0)) %>% 
  mutate(cov2_detected = ifelse(sars_cov2_detected == TRUE,
                                yes = 1,
                                no = 0)) %>% 
  mutate(has_pneumonia = ifelse(pna_type == "Non-Pneumonia Control",
                           yes = 0,
                           no = 1)) %>% 
  mutate(coinfection_detected = ifelse(any_nonviral == "TRUE",
                           yes = 1,
                           no = 0)) %>% 
  mutate(other_viral_pna = ifelse(pna_type == "Other Viral Pneumonia",
                           yes = 1,
                           no = 0)) %>% 
  mutate(nonviral_pna = ifelse(pna_type == "Other Pneumonia",
                           yes = 1,
                           no = 0)) %>% 
  mutate(is_healthy_control = ifelse(pna_type == "Healthy Control",
                           yes = 1,
                           no = 0)) %>% 
  dplyr::select(deceased, has_covid, cov2_detected, has_pneumonia,
                other_viral_pna, nonviral_pna, is_healthy_control,
                percent_neutrophils, percent_total_CD206_high,
                percent_CD4_total, percent_CD8_total, finite_day_of_intubation,
                C_Reactive_Protein, D_DIMER, PROCALCITONIN, mean_aps)
# Recalculate MEs with color labels
MEs0 = moduleEigengenes(all_counts, moduleColors)$eigengenes
MEs = orderMEs(MEs0)
moduleTraitCor = bicor(MEs, 
                     md_of_interest, 
                     use = "pairwise.complete.obs",
                     maxPOutliers = 0.05)
bicor: zero MAD in variable 'y'. Pearson correlation was used for individual columns with zero (or missing) MAD.
moduleTraitPvalue = corPvalueStudent(moduleTraitCor, 
                                     nSamples) %>% 
  as.numeric() %>% 
  p.adjust(., method = "fdr") %>% 
  matrix(ncol = ncol(moduleTraitCor))
colnames(moduleTraitPvalue) = colnames(moduleTraitCor)
rownames(moduleTraitPvalue) = rownames(moduleTraitCor)
moduleTraitCor_hm = t(moduleTraitCor)
#just make significant or not
pvals_hm = t(moduleTraitPvalue) %>% 
  as.matrix()
pvals_hm[pvals_hm < 0.05] = ""
pvals_hm[pvals_hm != ""] = "NS"

labs = c("Deceased", "COVID-19", "SARS-CoV-2 Detected", "Any Pneumonia", "Other Viral Pneumonia", "Other Pneumonia",
         "Healthy Control", "% Neutrophils", "% Macrophages CD206-high", "% CD4 T", "% CD8 T",
         "Day of Intubation", "CRP", "D-Dimer", "Procalcitonin", "Mean APS")
module_cor_heatmap = pheatmap(mat = moduleTraitCor_hm,
                              labels_row = labs,
                              labels_col = paste("Module", c(1:ncol(MEs))),
                              display_numbers = pvals_hm,
                              cluster_rows = T,
                              cluster_cols = T,
                              clustering_method = "ward.D2",
                              color = colorRampPalette(rev(brewer.pal(n = 7, 
                                                          name = "RdBu")))(100),
                              angle_col = 315)

module_cor_heatmap = pheatmap(mat = moduleTraitCor_hm,
                              labels_row = labs,
                              labels_col = paste("Module", c(1:ncol(MEs))),
                              display_numbers = pvals_hm,
                              cluster_rows = T,
                              cluster_cols = T,
                              clustering_method = "ward.D2",
                              color = colorRampPalette(rev(brewer.pal(n = 7, 
                                                          name = "RdBu")))(100),
                              angle_col = 315, 
                              fontsize_row = 32,
                              fontsize = 24)

Module 12 (turquoise) looks like the key MoAM cluster, 4 (blue) is key TRAM, and module 14 (purple) is likely our IFN cluster.

With vent settings

Module 13 (salmon) may also be interesting. Correlates with COVID, CRP, lymphocytes, and vent params!

Sanity check: are the CD206 modules TRAM/MoAM markers?

module_assignments = data.frame(ensembl_gene_id = colnames(all_counts),
                                module = factor(mergedColors)) %>% 
  left_join(., gene_conv)
Joining, by = "ensembl_gene_id"
write.csv(module_assignments,
          "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_WGCNA_module_assignments.csv")

cd206_correlated = subset(module_assignments, module == "turquoise")
cd206_anticorrelated = subset(module_assignments, module == "blue")
cd206_correlated
cd206_anticorrelated

Pretty ideal, yeah

COVID-associated

Purple contains all of the CoV-2 genes!

Pretty classic interferon response. Look at the GO.

#from k_means_figure
complete_counts = counts(mp_des, normalized = T)
universe = rownames(complete_counts[rowSums(complete_counts) > 0, ])
fisherTest = new("classicCount", testStatistic = GOFisherTest, name = "Fisher test")

cluster_genes = covid_correlated_cd206_uncorrelated$ensembl_gene_id
selection = as.numeric(universe %in% cluster_genes)
names(selection) = universe
go_data = new("topGOdata", 
              ontology = "BP", 
              allGenes = selection,
              geneSel = function(x){
                return(x == 1)},
              annot = annFUN.org, 
              mapping = "org.Hs.eg.db", 
              ID = "ensembl")

Building most specific GOs .....
    ( 12142 GO terms found. )

Build GO DAG topology ..........
    ( 16096 GO terms and 38209 relations. )

Annotating nodes ...............
    ( 16536 genes annotated to the GO terms. )
  
#run Fisher test
test_results = getSigGroups(go_data, fisherTest)

             -- Classic Algorithm -- 

         the algorithm is scoring 3412 nontrivial nodes
         parameters: 
             test statistic: Fisher test
module14_score = as.data.frame(score(test_results))
colnames(module14_score) = "pval"
module14_score = rownames_to_column(module14_score, var = "go_id")
  
#adjust p-values and take significant
module14_score$padj = p.adjust(module14_score$pval, method = "fdr")
module14_score = subset(module14_score, padj < 0.05)
module14_score$description = NA
for(i in 1:nrow(module14_score))
{
  module14_score$description[i] = GOTERM[[module14_score$go_id[i]]]@Term
}

#add descriptions
module14_score$full_go = paste(module14_score$go_id, module14_score$description)
write.csv(module14_score,
          "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_purple_module_14_GO.csv")
module14_score

Pretty much all Type I interferon related. Most of the paper is here.

Module 13

This module has IRF1 and the MHC-I genes

1
[1] 1
module13 = subset(module_assignments, module == "salmon")
module13
write.csv(module13,
          "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200721_salmon_module_13_genes.csv")
module13_score = subset(module13_score, padj < 0.05)
module13_score$description = NA
Error in `$<-.data.frame`(`*tmp*`, description, value = NA) : 
  replacement has 1 row, data has 0

No significant hits.

Plot interesting modules

Purple module (14) and diagnosis, outcome

total_umap = MEList$averageExpr %>% 
  rownames_to_column("sample") %>% 
  left_join(total_umap, .)
Joining, by = "sample"
covid_umap = total_umap %>% 
  dplyr::filter(covid_confirmed == TRUE)

ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = AEpurple, color = Diagnosis)) +
  geom_point()

module14_umap = ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = AEpurple, color = pna_type, shape = binned_outcome)) +
  geom_point() +
  theme_bw() +
  theme(text = element_text(size = 16, family = "Arial"),
        legend.text = element_text(size = 16, family = "Arial"),
        legend.title = element_text(size = 16, family = "Arial")) +
  scale_color_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non-Pneumonia Control" = fig2_pal[2],
                               "COVID-19" = fig2_pal[1],
                               "Other Viral Pneumonia" = fig2_pal[3],
                               "Other Pneumonia" = fig2_pal[4]),
                    na.value = "black") +
  scale_shape_manual(name = "",
                    values = c("Deceased" = 13,
                               "Discharged" = 19,
                               "Inpatient Facility" = 18,
                               "Other" = 18),
                               na.value = 1) +
  scale_size_continuous(name = "Module 14 Expression", 
                        range = c(1, 10)) +
  xlab("UMAP 1") +
  ylab("UMAP 2")
module14_umap 

CCL24

total_umap = left_join(total_umap, ccl24_counts)
Joining, by = "sample"
ccl24_umap = ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = CCL24, color = pna_type, shape = binned_outcome)) +
  geom_point() +
  theme_bw() +
  theme(text = element_text(size = 16, family = "Arial"),
        legend.text = element_text(size = 16, family = "Arial"),
        legend.title = element_text(size = 16, family = "Arial")) +
  scale_color_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non-Pneumonia Control" = fig2_pal[2],
                               "COVID-19" = fig2_pal[1],
                               "Other Viral Pneumonia" = fig2_pal[3],
                               "Other Pneumonia" = fig2_pal[4]),
                    na.value = "black") +
  scale_shape_manual(name = "",
                    values = c("Deceased" = 13,
                               "Discharged" = 19,
                               "Inpatient Facility" = 18,
                               "Other" = 18),
                               na.value = 1) +
scale_size_continuous(name = "CCL24 Counts", trans = "log10", range = c(1, 10)) +
  xlab("UMAP 1") +
  ylab("UMAP 2")
ccl24_umap 

This is really cool! This isolates most the the IFN-non-responsive COVID patients. Maybe this drives heterogeneity in celltype composition in the lung?

tcell_umap = ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = percent_CD3_total, color = pna_type, shape = binned_outcome)) +
  geom_point() +
  theme_bw() +
  theme(text = element_text(size = 16, family = "Arial"),
        legend.text = element_text(size = 16, family = "Arial"),
        legend.title = element_text(size = 16, family = "Arial")) +
  scale_color_manual(name = "",
                    values = c("Healthy_Control" = fig2_pal[6],
                               "Non-Pneumonia Control" = fig2_pal[2],
                               "COVID-19" = fig2_pal[1],
                               "Other Viral Pneumonia" = fig2_pal[3],
                               "Other Pneumonia" = fig2_pal[4]),
                    na.value = "black") +
  scale_shape_manual(name = "",
                    values = c("Deceased" = 13,
                               "Discharged" = 19,
                               "Inpatient Facility" = 18,
                               "Other" = 18),
                               na.value = 1) +
scale_size_continuous(name = "Percent Lymphocytes", range = c(1, 10)) +
  xlab("UMAP 1") +
  ylab("UMAP 2")

tcell_umap 

Brown/turquoise modules and day of intubation in COVID patients

TRAM content

ggplot(total_umap, aes(x = day_of_intubation, y = AEblue)) +
  geom_point() +
  geom_smooth()


ggplot(total_umap, aes(x = day_of_intubation, y = AEturquoise)) +
  geom_point() +
  geom_smooth()

Not much of a correlation…maybe a flat line, as I guess would be expected with near-constant recruitment.

Effect of ORF8 expression

Isolate counts

orf8 = cov2_genes$ensembl_gene_id[which(cov2_genes$gene_name == "ORF8")]
orf8_counts = plotCounts(mp_des, 
                         gene = orf8, 
                         intgroup = "pna_type",
                         returnData = T,
                         normalized = T, 
                         pc = T)
orf8_samples = rownames(subset(orf8_counts, count >0))

ggplot(orf8_counts, aes(x = pna_type, y = count)) +
  geom_boxplot() +
  geom_jitter(aes(color = count > 0)) +
  scale_y_log10() +
  ylab("ORF8 Counts") +
  xlab("") 

Not a ton of detection but very clean.

Association with interferon responses

mp_des$orf8_detected = mp_des$sample %in% orf8_samples
total_umap$orf8_detected = total_umap$sample %in% orf8_samples
ggplot(total_umap, aes(x = UMAP_1, y = UMAP_2, size = MEpurple, color = Diagnosis, shape = orf8_detected)) +
  geom_point()

Pretty clear spatial correlation…but in the opposite direction?

ggplot(total_umap, aes(x = orf8_detected, y = MEpurple)) +
  geom_boxplot() +
  geom_jitter(aes(color = Diagnosis))

high_cov2 = colnames(cov2_counts)[colSums(cov2_counts) > 50]
total_umap$cov2_detected = total_umap$sample %in% high_cov2
ggplot(total_umap, aes(x = cov2_detected, y = MEpurple)) +
  geom_boxplot() +
  geom_jitter(aes(color = Diagnosis))

This really just correlates with overall viral load (which correlates, in turn, with ORF8 levels). No support really for the ORF8 inhibition of the IFN response, at least at this stage.

Interferon response over time

WGCNA Module purple

Average expression

GO Categories

Pull from biomart

#now pull down genes based on gene ontology (GO) definitions
typeI_IFN_response = getBM(attributes = c("ensembl_gene_id", "external_gene_name"),
                           filters = "go",
                           values = "GO:0060337",
                           mart = human_mart)
Error in martCheck(mart) : 
  No dataset selected, please select a dataset first.  You can see the available datasets by using the listDatasets function see ?listDatasets for more information.  Then you should create the Mart object by using the useMart function.  See ?useMart for more information

Assign mean expression

covid_umap = covid_umap %>% 
  dplyr::select(-c(typeI_IFN_response, IFNg_response, general_IFN_response)) %>% 
  left_join(., type1_counts) %>% 
  left_join(., type2_counts) %>% 
  left_join(., ifn_counts)
Joining, by = "sample"
Joining, by = "sample"
Joining, by = "sample"

Plot

Correlations

cor.test(covid_umap$typeI_IFN_response, covid_umap$finite_day_of_intubation)

    Pearson's product-moment correlation

data:  covid_umap$typeI_IFN_response and covid_umap$finite_day_of_intubation
t = -4.2101, df = 77, p-value = 6.854e-05
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.5966184 -0.2338266
sample estimates:
       cor 
-0.4325723 
cor.test(covid_umap$IFNg_response, covid_umap$finite_day_of_intubation)

    Pearson's product-moment correlation

data:  covid_umap$IFNg_response and covid_umap$finite_day_of_intubation
t = -1.6981, df = 77, p-value = 0.09353
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.39452624  0.03248575
sample estimates:
       cor 
-0.1899893 
cor.test(covid_umap$general_IFN_response, covid_umap$finite_day_of_intubation)

    Pearson's product-moment correlation

data:  covid_umap$general_IFN_response and covid_umap$finite_day_of_intubation
t = -3.5506, df = 77, p-value = 0.0006593
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.5505383 -0.1679018
sample estimates:
       cor 
-0.3750871 

Second batch of pico optimization

Let’s focus on interferon-hi vs interferon-low samples
### Identify interesting

last_batch = c(300312389, 304012699, 304017553, 304020298, 304020362,
               340224808, 340233896, 340239789, 340239790, 340239805)
good_samples = mp_des[, ((!is.na(mp_des$RIN) & mp_des$RIN >= 7) & 
                    mp_des$STAR_mqc_generalstats_star_uniquely_mapped_percent >= 30 &
                    mp_des$featureCounts_mqc_generalstats_featurecounts_percent_assigned >= 30) &
                    mp_des$RNA_concentration_pg_ul >= 125]
remaining_interesting = setdiff(good_samples$sample, last_batch)
interesting_metadata = subset(total_umap, sample %in% remaining_interesting)
table(interesting_metadata$pna_type)
ggplot(interesting_metadata, aes(x = pna_type, y = AEpurple)) +
  geom_boxplot()
selection = interesting_metadata %>% 
  filter(pna_type != "Other Pneumonia" | sample == 340235110) %>% 
  dplyr::select(sample, tube_loc_macrophRNA_boxID, RNA_concentration_pg_ul) %>% 
  mutate(dilution = ifelse((250 / RNA_concentration_pg_ul) < 0.4,
                           yes = round(1 / (250 / RNA_concentration_pg_ul) / 5) * 5,
                           no = 1)) %>% 
  mutate(vol_for_250_pg = round(250 / RNA_concentration_pg_ul * dilution, digits = 2))
write.csv(selection, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/200713_pico_opt_batch2.csv")
selection

Conclusions

Output data for posterity

final_counts_raw = counts(mp_des, normalized = F)

#clean metadata for safe sharing
final_md_safe = colData(mp_des) %>% 
  as.data.frame() %>% 
  dplyr::select(sample, age, sex, race = races, ethnicity, diagnosis = pna_type, 
                day_of_ventilation = finite_day_of_intubation, study_id)
#convert script IDs to new identifiers
id_conv = data.frame(script_id = sample(unique(final_md_safe$study_id))) %>% #shuffle IDs first
  mutate(anonymized_patient_id = sprintf("%04d", 1:nrow(id_conv)))
#add back to md
final_md_safe = left_join(final_md_safe, id_conv, by = c("study_id" = "script_id")) %>% 
  dplyr::select(-study_id)

write.csv(final_counts_raw, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/GEO_output/200724_raw_counts_geo.csv")
write.csv(final_md_safe, "/projects/b1038/Pulmonary/rgrant/script_bulk/Analysis/GEO_output/200724_deidentified_metadata_geo.csv")
LS0tCnRpdGxlOiAiU0NSSVBUIEJ1bGsgSGlnaC1MZXZlbCBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBHb2FscyAgIAoxLiBJZGVudGlmeSB0cmFuc2NyaXB0aW9uYWwgcGF0dGVybnMgaW4gQU0gYXNzb2NpYXRlZCB3aXRoIElBViwgQ09WSUQtMTksIGFuZCBjb21tb24gdG8gYm90aCAgIAoyLiBEZXRlcm1pbmUgc291cmNlIG9mIElMNiBhbmQgSUwxQiBpbiB0aGUgbHVuZyAoaWYgcG9zc2libGUpICAgCiAgIAojIFNldHVwICAgCiMjIExvYWQgcGFja2FnZXMgICAKYGBge3Igc2V0dXB9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShERVNlcTIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkocGFyYWxsZWwpCmxpYnJhcnkodXdvdCkKbGlicmFyeShXR0NOQSkKbGlicmFyeShnZ3NjaSkKbGlicmFyeSh0b3BHTykKbGlicmFyeShHTy5kYikKbGlicmFyeShvcmcuSHMuZWcuZGIpCmxpYnJhcnkocGFyYWxsZWwpCmxpYnJhcnkoZG9QYXJhbGxlbCkKbGlicmFyeShiaW9tYVJ0KQpyZWdpc3RlckRvUGFyYWxsZWwobWFrZUNsdXN0ZXIoMTIpKQpyZWdpc3RlcihNdWx0aWNvcmVQYXJhbSgxMikpCm9wdGlvbnMoZ3N1YmZuLmVuZ2luZSA9ICJSIikKc2V0LnNlZWQoMTIzNDUpCnNvdXJjZSgifi91dGlscy9SL3ByZXR0eV9NQV9wbG90LlIiKQpzb3VyY2UoIn4vdXRpbHMvUi9rX21lYW5zX2ZpZ3VyZS5SIikKc291cmNlKCJ+L3V0aWxzL1IvcGxvdFBDQV9tYW51YWwuUiIpCmZpZzJfcGFsID0gcGFsX25wZygibnJjIikoOSkKCnNlc3Npb25JbmZvKCkKYGBgCgojIyBJbXBvcnQgZGF0YSAgIApgYGB7cn0KbXAgPSByZWFkUkRTKCIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MjFfc2NyaXB0X2J1bGtfZGVzX25vX2hVUk5BLnJkcyIpCm1wJGNvdmlkX2NvbmZpcm1lZCA9IGZhY3RvcihtcCRjb3ZpZF9jb25maXJtZWQpCm1wJHNleCA9IGZhY3RvcihtcCRnZW5kZXIpCgojc2V0IHVwIGZvciBjb21wYXJpc29uIGJ5IGRpYWdub3NpcwptcCREaWFnbm9zaXMgPSBnc3ViKCItfCAiLCAiXyIsIGFzLmNoYXJhY3RlcihtcCRwbmFfdHlwZSkpCm1wJERpYWdub3NpcyA9IGZhY3RvcihtcCREaWFnbm9zaXMsIAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiSGVhbHRoeV9Db250cm9sIiwgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIsICJDT1ZJRF8xOSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfVmlyYWxfUG5ldW1vbmlhIiwgIk90aGVyX1BuZXVtb25pYSIpKQptcCRuZXV0cm9waGlsaWMgPSBtcCRwZXJjZW50X25ldXRyb3BoaWxzID4gNTAKI2ZvciBtb2RlbGluZywgZXRjCm1wJGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiA9IG1wJGRheV9vZl9pbnR1YmF0aW9uCm1wJGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbltpcy5pbmZpbml0ZShtcCRmaW5pdGVfZGF5X29mX2ludHViYXRpb24pXSA9IE5BCm1wJGRheTBfc2FtcGxlID0gZmFjdG9yKG1wJGRheV9vZl9pbnR1YmF0aW9uID49IDAgJiBtcCRkYXlfb2ZfaW50dWJhdGlvbiA8PTIpCm1wJGRheTBfc2FtcGxlW2lzLm5hKG1wJGRheTBfc2FtcGxlKV0gPSBGQUxTRQpkZXNpZ24obXApID0gYXMuZm9ybXVsYSgifiBEaWFnbm9zaXMiKQptZXRhZGF0YSA9IGFzLmRhdGEuZnJhbWUoY29sRGF0YShtcCkpCmBgYCAgIAogICAKIyMgU3VtbWFyeSBzdGF0cyAgIAojIyMgTnVtYmVyIG9mIHNhbXBsZXMgb3ZlcmFsbCAgIApgYGB7cn0KdGFibGUobXBfZGVzJGNvdmlkX2NvbmZpcm1lZCkKYGBgCgojIyMgTnVtYmVyIG9mIHNlcmlhbCBzYW1wbGVzICAgCmBgYHtyfQpuX3NhbXBsZXMgPSB0YWJsZShtZXRhZGF0YSRwYXRpZW50X2lkKQpzZXJpYWxfcGF0aWVudHMgPSBuYW1lcyhuX3NhbXBsZXNbbl9zYW1wbGVzID4gMV0pCmxlbmd0aChzZXJpYWxfcGF0aWVudHMpCmBgYCAgIAogICAKIyMjIERpc3RyaWJ1dGlvbiBvZiBkYXlzICAgCmBgYHtyfQpnZ3Bsb3QobWV0YWRhdGEsIGFlcyh4ID0gZGF5X29mX2ludHViYXRpb24pKSArCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICJkb2RnZXJibHVlNCIpCmBgYAogICAKIyMgUENBICAgCiMjIyBDYWxjdWxhdGUgYW5kIG9yZ2FuaXplICAgCmBgYHtyfQptcF92c3QgPSB2c3QobXAsIG5zdWIgPSAzMDAwLCBmaXRUeXBlID0gImxvY2FsIikgI2tub3cgZnJvbSBsYXRlciB0aGF0IGxvY2FsIGlzIGJlc3QKbXBfY291bnRzID0gY291bnRzKGVzdGltYXRlU2l6ZUZhY3RvcnMobXApLCBub3JtYWxpemVkID0gVCkKcGNhX2RhdGEgPSBwbG90UENBX21hbnVhbChtcF92c3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaW50Z3JvdXAgPSBjKCJjb3ZpZF9jb25maXJtZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBwY3MgPSAxMCkKcGNhX2RhdGEkZGF0YSA9IGxlZnRfam9pbihwY2FfZGF0YSRkYXRhLAogICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKGNvbERhdGEobXApKSwKICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJuYW1lIiA9ICJzYW1wbGUiLCAiY292aWRfY29uZmlybWVkIikpCgojbWVyZ2UgY291bnRzIGFuZCBwY2EgZGF0YQpnZW5lX2NvbnYgPSBhcy5kYXRhLmZyYW1lKHJvd0RhdGEobXApKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJlbnNlbWJsX2dlbmVfaWQiKQptZXJnZV9jb3VudHMgPSBtcF9jb3VudHMgJT4lIAogIHQoKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAibmFtZSIpCgojbWVyZ2UgdG9nZXRoZXIgZm9yIGZlYXR1cmVwbG90IGRhdGFzZXQKZnBfZGF0YSA9IGxlZnRfam9pbihwY2FfZGF0YSRkYXRhLCBtZXJnZV9jb3VudHMsIGJ5ID0gIm5hbWUiKQpgYGAKCiMjIyBIb3cgbWFueSBQQ3M/ICAgCmBgYHtyfQojc2NyZWUgcGxvdCAgIApmdml6X2VpZyhwY2FfZGF0YSRwY2EsIAogICAgICAgICBiYXJmaWxsID0gImRvZGdlcmJsdWU0IiwgCiAgICAgICAgIHhsYWIgPSAiUHJpbmNpcGFsIENvbXBvbmVudCIsCiAgICAgICAgIHlsYWIgPSAiUGVyY2VudCBWYXJpYW5jZSBFeHBsYWluZWQiLCAKICAgICAgICAgbWFpbiA9ICIiLAogICAgICAgICBuY3AgPSA1MCwKICAgICAgICAgZ2d0aGVtZSA9IHRoZW1lX2J3KCksCiAgICAgICAgIGFkZGxhYmVscyA9IFQpICM0LTUgUENzIHdpbGwgZG8gaXQKYGBgCiAgIAojIyMgRXhhbWluZSBsb2FkaW5ncyAgIApgYGB7cn0KbG9hZGluZ3MgPSBwY2FfZGF0YSRwY2Ekcm90YXRpb24gJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgcmlnaHRfam9pbihnZW5lX2NvbnYsIC4pCmBgYAoKICAgCiMjIyBQQzE6IE1vQU0gQ2hhcmFjdGVyICAgCmBgYHtyfQpnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIHNoYXBlID0gY292aWRfY29uZmlybWVkLCBjb2xvciA9IHBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKQpmYWJwNF9wbG90ID0gZ2dwbG90KGZwX2RhdGEsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGxvZzIoRU5TRzAwMDAwMTcwMzIzKSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMobmFtZSA9ICJMb2cyKEZBQlA0IENvdW50cykiKQpzcHAxX3Bsb3QgPSBnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gbG9nMihFTlNHMDAwMDAxMTg3ODUpKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhuYW1lID0gIkxvZzIoU1BQMSBDb3VudHMpIikKZmFicDRfcGxvdCArIHNwcDFfcGxvdApgYGAgICAKICAgIAojIyMgUEMyOiBQYXR0ZXJucyBvZiBhY3RpdmF0aW9uIChhbHNvIGJ5IG1pbGlldSkgICAKYGBge3J9CmdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgc2hhcGUgPSBjb3ZpZF9jb25maXJtZWQsIGNvbG9yID0gQ19SZWFjdGl2ZV9Qcm90ZWluKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpCmdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgc2hhcGUgPSBjb3ZpZF9jb25maXJtZWQsIGNvbG9yID0gTERIKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpCmdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgc2hhcGUgPSBjb3ZpZF9jb25maXJtZWQsIGNvbG9yID0gRkVSUklUSU4pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykKaW5oYmFfcGxvdCA9IGdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBsb2cyKEVOU0cwMDAwMDEyMjY0MSkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKG5hbWUgPSAiTG9nMihJTkhCQSkiKQppbDFiX3Bsb3QgPSBnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gbG9nMihFTlNHMDAwMDAxMjU1MzgpKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhuYW1lID0gIkxvZzIoSUwxYikiKQpgYGAKQWZ0ZXIgYWRkaW5nIGhlYWx0aHkgY29udHJvbHMgdGhpcyBpcyBsb25nZXIgdHJ1ZS4gICAKCiAgIAojIyMgUEMzOiBNYWxlL2ZlbWFsZT8gICAKYGBge3J9CmdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMiwgeSA9IFBDMywgY29sb3IgPSBnZW5kZXIpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykKeGlzdF9wbG90ID0gZ2dwbG90KGZwX2RhdGEsIGFlcyh4ID0gUEMyLCB5ID0gUEMzLCBjb2xvciA9IGxvZzIoRU5TRzAwMDAwMjI5ODA3KSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMobmFtZSA9ICJMb2cyKFhJU1QpIikKYGBgICAgCk5vdCByZWFsbHkgICAKICAgCiMjIyBDb25kaXRpb24KYGBge3J9CmdncGxvdChmcF9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBEaWFnbm9zaXMpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIHN0YXRfZWxsaXBzZSgpCmBgYCAgIAogICAKIyMjIERheSBvZiBpbnR1YmF0aW9uCmBgYHtyfQpnZ3Bsb3QoZnBfZGF0YSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG9yID0gbG9nMihkYXlfb2ZfaW50dWJhdGlvbikpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykKYGBgICAgCk5vIGNsZWFyIHNlcGFyYXRpb24uICAgCiAgIAojIyBEZXRlcm1pbmUgYmVzdCBkaXNwZXJzaW9uIGVzdGltYXRlcyAgIAojIyMgUGFyYW1ldHJpYyAgIApgYGB7cn0KI25vdGU6IERFU2VxIGlzIHJlZml0dGluZyBmYXIgdG9vIG1hbnkgZ2VuZXMuIE5lZWQgdG8gdHVybiB0aGlzIG9mZi4KbXBfZGVzX3BhcmFtZXRyaWMgPSBERVNlcShtcCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZml0VHlwZSA9ICJwYXJhbWV0cmljIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWluUmVwbGljYXRlc0ZvclJlcGxhY2UgPSBJbmYpCnBsb3REaXNwRXN0cyhtcF9kZXNfcGFyYW1ldHJpYywgY2V4ID0gMC4xKQpgYGAgICAKICAgClRoaXMgZml0IHJlYWxseSBpc24ndCBiYWQsIGJ1dCBvdmVyZXN0aW1hdGVzIGF0IGxvd2VyIGV4cHJlc3Npb24gKHByb2JhYmx5IG5vdCBhIGh1Z2UgZGVhbCkuICAgCiAgICAKIyMjIExvY2FsCmBgYHtyfQptcF9kZXNfbG9jYWwgPSBERVNlcShtcCwKICAgICAgICAgICAgICAgICAgICAgZml0VHlwZSA9ICJsb2NhbCIsCiAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsID0gVCwKICAgICAgICAgICAgICAgICAgICAgbWluUmVwbGljYXRlc0ZvclJlcGxhY2U9SW5mKQpwbG90RGlzcEVzdHMobXBfZGVzX2xvY2FsLCBjZXggPSAwLjEpCgptcF9kZXMgPSBtcF9kZXNfbG9jYWwKcm0obXBfZGVzX2xvY2FsLCBtcF9kZXNfcGFyYW1ldHJpYykKYGBgICAKU3RpbGwgbm90IHBlcmZlY3QsIGJ1dCBhIGxvdCBiZXR0ZXIuICAgCiAgIApgYGB7cn0KI3VzZWQgYSBmZXcgdGltZXMgbGF0ZXI7IHNhZmVzdCB0byBwdXQgaGVyZQojaWRlbnRpZnkgaW5mZWN0ZWQgc2FtcGxlcwpub25faHVtYW5fZ2VuZXMgPSBzdWJzZXQoZ2VuZV9jb252LCAhKGdyZXBsKCJeRU5TRyIsIGVuc2VtYmxfZ2VuZV9pZCkpKSAjaHVtYW4gZ2VuZXMgYWxsIGhhdmUgdGhpcyBwcmVmaXgKbm9uX2h1bWFuX2dlbmVzJGdlbmVfbmFtZVtub25faHVtYW5fZ2VuZXMkZW5zZW1ibF9nZW5lX2lkID09ICJnZW5lLVVKOTlfczZncDEiXSA9ICJOQSIgI25ldXJhbWluaWRhc2Ugd2FzIG1pc3JlYWQKbm9uX2h1bWFuX2dlbmVzJHZpcnVzID0gZmFjdG9yKGlmZWxzZShncmVwbCgiVUo5OSIsIG5vbl9odW1hbl9nZW5lcyRlbnNlbWJsX2dlbmVfaWQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gIkluZmx1ZW56YSBBL0NhbGlmb3JuaWEvMDcvMjAwOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9ICJTQVJTLUNvVi0yIikpCmNvdjJfZ2VuZXMgPSBzdWJzZXQobm9uX2h1bWFuX2dlbmVzLCBncmVwbCgiU0FSU3xHVTI4MCIsIGVuc2VtYmxfZ2VuZV9pZCkpCmlhdl9nZW5lcyA9IHN1YnNldChub25faHVtYW5fZ2VuZXMsIGdyZXBsKCJVSjk5IiwgZW5zZW1ibF9nZW5lX2lkKSkKZmx1X2NvdW50cyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBUKVtpYXZfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLCBdCmZsdV9kZXRlY3RlZCA9IGNvbG5hbWVzKGZsdV9jb3VudHNbLCBjb2xTdW1zKGZsdV9jb3VudHMpID4gMF0pCmNvdjJfY291bnRzID0gY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IFQpW2NvdjJfZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLCBdCmNvdjJfZGV0ZWN0ZWQgPSBjb2xuYW1lcyhjb3YyX2NvdW50c1ssIGNvbFN1bXMoY292Ml9jb3VudHMpID4gMF0pCm1wX2RlcyRzYXJzX2NvdjJfZGV0ZWN0ZWQgPSBmYWN0b3IobXBfZGVzJHNhbXBsZSAlaW4lIGNvdjJfZGV0ZWN0ZWQpCm1wX2RlcyRpYXZfaDFuMV9kZXRlY3RlZCA9IGZhY3RvcihtcF9kZXMkc2FtcGxlICVpbiUgZmx1X2RldGVjdGVkKQoKIyMgUmVwbGljYXRpbmcgQ29WMiBzYW1wbGVzCiMjIyBvdmVyYWxsCmFudGlzZW5zZV9jb3VudHMgPSBjb3YyX2NvdW50c1siU0FSU19Db1ZfMl9hbnRpc2Vuc2VfZ2Vub21lIiwgXQpzZW5zZV9jb3VudHMgPSBjb3YyX2NvdW50c1syOm5yb3coY292Ml9jb3VudHMpLCBdCnJlcGxpY2F0aW5nX2NvdjIgPSBpbnRlcnNlY3QobmFtZXMoYW50aXNlbnNlX2NvdW50cylbYW50aXNlbnNlX2NvdW50cyA+IDBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKHNlbnNlX2NvdW50c1ssIGNvbFN1bXMoc2Vuc2VfY291bnRzKSA+IDBdKSkKIyMjIGp1c3QgY292aWQKcGVyY2VudF9kZXRlY3RlZF9jb3ZpZCA9IGxlbmd0aCh1bmlxdWUoc3Vic2V0KG1ldGFkYXRhLCBzYW1wbGUgJWluJSBjb3YyX2RldGVjdGVkICYgY292aWRfY29uZmlybWVkID09IFRSVUUpJHN0dWR5X2lkKSkgLyBsZW5ndGgodW5pcXVlKHN1YnNldChtZXRhZGF0YSwgY292aWRfY29uZmlybWVkID09IFRSVUUpJHN0dWR5X2lkKSkgKiAxMDAKcGVyY2VudF9kZXRlY3RlZF9jb3ZpZApwZXJjZW50X3JlcGxpY2F0aW5nX2NvdmlkID0gbGVuZ3RoKHVuaXF1ZShzdWJzZXQobWV0YWRhdGEsIHNhbXBsZSAlaW4lIHJlcGxpY2F0aW5nX2NvdjIgJiBjb3ZpZF9jb25maXJtZWQgPT0gVFJVRSkkc3R1ZHlfaWQpKSAvIGxlbmd0aCh1bmlxdWUoc3Vic2V0KG1ldGFkYXRhLCBjb3ZpZF9jb25maXJtZWQgPT0gVFJVRSkkc3R1ZHlfaWQpKSAqIDEwMApwZXJjZW50X3JlcGxpY2F0aW5nX2NvdmlkCgpwZXJjZW50X3JlcGxpY2F0aW5nX2NvdmlkIC8gcGVyY2VudF9kZXRlY3RlZF9jb3ZpZCAqIDEwMApgYGAKICAgICAgCiMjIFNhbml0eSBjaGVja3MgIAojIyMgU0FSUy1Db1YtMiAgIApEb2VzIGV4cHJlc3Npb24gb2YgdmlyYWwgZ2VuZXMgY29ycmVsYXRlIHdpdGggY292aWQgZGlhZ25vc2lzPyAgIApgYGB7cn0KY292Ml9jb3VudHMgPSBsYXBwbHkoY292Ml9nZW5lcyRlbnNlbWJsX2dlbmVfaWQsIGZ1bmN0aW9uKHgpewogIGNvdW50cyA9IHBsb3RDb3VudHMobXAsCiAgICAgICAgICAgICAgICAgICAgICBnZW5lID0geCwKICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gIkRpYWdub3NpcyIsCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICBwYyA9IFQpCiAgY291bnRzJGdlbmUgPSB4CiAgcmV0dXJuKGNvdW50cyl9KQpjb3YyX2NvdW50cyA9IGJpbmRfcm93cyhjb3YyX2NvdW50cykKCmdncGxvdChjb3YyX2NvdW50cywgYWVzKHggPSBEaWFnbm9zaXMsIHkgPSBjb3VudCwgZmlsbCA9IGdlbmUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHNjYWxlX3lfbG9nMTAoKQpgYGAgICAKTm93IHRoYXQgd2UgaGF2ZSBhbGwgb2YgdGhlIG5lY2Vzc2FyeSBtZXRhZGF0YSwgdGhpcyBsb29rcyBmYW50YXN0aWMuICAKICAgCgogICAgICAKIyMjIERvIGNvdW50cyBjbHVzdGVyIGJ5IHZpcnVzIGFuZCBkaWFnbm9zaXM/ICAgCmBgYHtyfQp2aXJhbF9jb3VudHMgPSBjb3VudHMobXBfZGVzLCBub3JtYWxpemVkID0gVCkgCnZpcmFsX2NvdW50cyA9IHZpcmFsX2NvdW50c1tub25faHVtYW5fZ2VuZXMkZW5zZW1ibF9nZW5lX2lkLCBdCnZpcmFsX2NvdW50cyA9IGxvZzEwKHZpcmFsX2NvdW50cyArIDAuNSkKCnZpcnVzX2RldGVjdGlvbiA9IHZlY3Rvcihtb2RlID0gImNoYXJhY3RlciIsIGxlbmd0aCA9IG5jb2wobXBfZGVzKSkKZm9yKGkgaW4gMTpuY29sKG1wX2RlcykpCnsKICBoYXNfY292aWQgPSBtcF9kZXMkY292aWRfY29uZmlybWVkW2ldID09IFRSVUUKICBoYXNfaWF2X2gxbjEgPSBtcF9kZXMkSU5GTFVFTlpBX0FfSDFfMjAwOVtpXSA9PSAiUG9zaXRpdmUiCiAgaGFzX290aGVyX2Nvcm9uYXZpcnVzID0gbXBfZGVzJGFueV9jb3JvbmF2aXJ1c19ub25fY292aWRbaV0gPT0gVFJVRQogICNyZWNvZGUgTkEgYXMgRkFMU0UgZm9yIHNhZmV0eQogIGlmKGlzLm5hKGhhc19pYXZfaDFuMSkpIAogIHsKICAgIGhhc19pYXZfaDFuMSA9IEZBTFNFCiAgfQogIGlmKGlzLm5hKGhhc19vdGhlcl9jb3JvbmF2aXJ1cykpIAogIHsKICAgIGhhc19vdGhlcl9jb3JvbmF2aXJ1cyA9IEZBTFNFCiAgfQogIAogIGlmKGhhc19jb3ZpZCA9PSBUUlVFICYmIGhhc19pYXZfaDFuMSA9PSBUUlVFICYmIGhhc19vdGhlcl9jb3JvbmF2aXJ1cyA9PSBUUlVFKQogIHsKICAgIHZpcnVzX2RldGVjdGlvbltpXSA9ICJTQVJTLUNvVi0yICYgT3RoZXIgQ29yb25hdmlydXMgJiBJbmZsdWVuemEgQS9DYWxpZm9ybmlhLzA3LzIwMDkiCiAgfSBlbHNlIGlmKGhhc19jb3ZpZCA9PSBUUlVFICYmIGhhc19pYXZfaDFuMSA9PSBGQUxTRSAmJiBoYXNfb3RoZXJfY29yb25hdmlydXMgPT0gRkFMU0UpCiAgewogICAgdmlydXNfZGV0ZWN0aW9uW2ldID0gIlNBUlMtQ29WLTIiCiAgfSBlbHNlIGlmKGhhc19jb3ZpZCA9PSBGQUxTRSAmJiBoYXNfaWF2X2gxbjEgPT0gVFJVRSAmJiBoYXNfb3RoZXJfY29yb25hdmlydXMgPT0gRkFMU0UpCiAgewogICAgdmlydXNfZGV0ZWN0aW9uW2ldID0gIkluZmx1ZW56YSBBL0NhbGlmb3JuaWEvMDcvMjAwOSIKICB9IGVsc2UgaWYoaGFzX2NvdmlkID09IEZBTFNFICYmIGhhc19pYXZfaDFuMSA9PSBGQUxTRSAmJiBoYXNfb3RoZXJfY29yb25hdmlydXMgPT0gVFJVRSkKICB7CiAgICAgdmlydXNfZGV0ZWN0aW9uW2ldID0gIk90aGVyIENvcm9uYXZpcnVzIgogIH0gZWxzZSBpZihoYXNfY292aWQgPT0gVFJVRSAmJiBoYXNfaWF2X2gxbjEgPT0gVFJVRSAmJiBoYXNfb3RoZXJfY29yb25hdmlydXMgPT0gRkFMU0UpCiAgewogICAgdmlydXNfZGV0ZWN0aW9uW2ldID0gIlNBUlMtQ29WLTIgJiBJbmZsdWVuemEgQS9DYWxpZm9ybmlhLzA3LzIwMDkiCiAgfSBlbHNlIGlmKGhhc19jb3ZpZCA9PSBUUlVFICYmIGhhc19pYXZfaDFuMSA9PSBGQUxTRSAmJiBoYXNfb3RoZXJfY29yb25hdmlydXMgPT0gVFJVRSkKICB7CiAgICB2aXJ1c19kZXRlY3Rpb25baV0gPSAiU0FSUy1Db1YtMiAmIE90aGVyIENvcm9uYXZpcnVzIgogIH0gZWxzZSBpZihoYXNfY292aWQgPT0gRkFMU0UgJiYgaGFzX2lhdl9oMW4xID09IFRSVUUgJiYgaGFzX290aGVyX2Nvcm9uYXZpcnVzID09IFRSVUUpCiAgewogICAgdmlydXNfZGV0ZWN0aW9uW2ldID0gIk90aGVyIENvcm9uYXZpcnVzICYgSW5mbHVlbnphIEEvQ2FsaWZvcm5pYS8wNy8yMDA5IgogIH0gZWxzZQogIHsKICAgIHZpcnVzX2RldGVjdGlvbltpXSA9IE5BCiAgfQp9Cm1wX2RlcyRkZXRlY3RlZF92aXJ1c2VzID0gZmFjdG9yKHZpcnVzX2RldGVjdGlvbikKICAKZGlhZ25vc2lzX2Fubm90YXRpb24gPSBhcy5kYXRhLmZyYW1lKGNvbERhdGEobXBfZGVzKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoRGlhZ25vc2lzID0gZGV0ZWN0ZWRfdmlydXNlcykKZ2VuZV9hbm5vdGF0aW9uID0gbm9uX2h1bWFuX2dlbmVzICU+JSAKICByZW1vdmVfcm93bmFtZXMoKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChgVmlyYWwgT3JpZ2luYCA9IHZpcnVzKQpnZW5lX25hbWVzID0gbm9uX2h1bWFuX2dlbmVzJGdlbmVfbmFtZQpnZW5lX25hbWVzW2dlbmVfbmFtZXMgPT0gIlNBUlNfQ29WXzJfYW50aXNlbnNlX2dlbm9tZSJdID0gIkFudGlzZW5zZSIKCnZpcmFsX2V4cHJlc3Npb25faGVhdG1hcCA9IHBoZWF0bWFwKHZpcmFsX2NvdW50cywKICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwKICAgICAgICBzaG93X2NvbG5hbWVzID0gRiwKICAgICAgICBjb2xvciA9IGluZmVybm8oMTAwKSwKICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGRpYWdub3Npc19hbm5vdGF0aW9uLAogICAgICAgIGFubm90YXRpb25fcm93ID0gZ2VuZV9hbm5vdGF0aW9uLAogICAgICAgIGxhYmVsc19yb3cgPSBnZW5lX25hbWVzLAogICAgICAgIGFubm90YXRpb25fY29sb3JzID0gbGlzdChEaWFnbm9zaXMgPSBjKCJTQVJTLUNvVi0yIiA9IGZpZzJfcGFsWzFdLCAiT3RoZXIgQ29yb25hdmlydXMiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbmZsdWVuemEgQS9DYWxpZm9ybmlhLzA3LzIwMDkiID0gZmlnMl9wYWxbM10sICJPdGhlciBDb3JvbmF2aXJ1cyAmIEluZmx1ZW56YSBBL0NhbGlmb3JuaWEvMDcvMjAwOSIgPSBmaWcyX3BhbFs0XSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgVmlyYWwgT3JpZ2luYCA9IGMoIlNBUlMtQ29WLTIiID0gZmlnMl9wYWxbMV0sICJJbmZsdWVuemEgQS9DYWxpZm9ybmlhLzA3LzIwMDkiID0gZmlnMl9wYWxbM10pKSwKICAgICAgICBhbmdsZV9jb2wgPSA0NSwgCiAgICAgICAgYW5ub3RhdGlvbl9uYW1lc19yb3cgPSBGKQpgYGAKICAgCiMjIyBQYXRpZW50IDExNzQgICAKVGhpcyBwYXRpZW50IGFwcGFyZW50bHkgbWV0IGNyaXRlcmlhIGZvciBDT1ZJRCB3ZWxsIGJlZm9yZSB0aGUgZmlyc3Qga25vd24gY2FzZXMgaW4gQ2hpY2FnbyAgIApgYGB7cn0KY292Ml9jb3VudHMgPSBjb3VudHMobXBfZGVzLCBub3JtYWxpemVkID0gVClbY292Ml9nZW5lcyRlbnNlbWJsX2dlbmVfaWQsIF0Kc2FtcGxlc18xMTc0ID0gbXBfZGVzJHN0dWR5X2lkID09ICIxMTc0IgpzYW1wbGVzXzExNzRbaXMubmEoc2FtcGxlc18xMTc0KV0gPSBGQUxTRQp0dWJlc18xMTc0ID0gbXBfZGVzJHNhbXBsZVtzYW1wbGVzXzExNzRdCmNvdjJfY291bnRzXzExNzQgPSBjb3YyX2NvdW50c1ssIHR1YmVzXzExNzRdCmNvdjJfY291bnRzXzExNzQKYGBgCk5vIGRldGVjdGlvbiwgYXQgbGVhc3QgaW4gbWFjcm9waGFnZXMuICAgCiAgIAojIyMgRG8gQ29WMiByZWFkcyBkZWNyZWFzZSBvdmVyIHRpbWU/ICAgCkNoZWNraW5nIGZvciB2aXJhbCBjbGVhcmFuY2UgICAKYGBge3J9CmNvdmlkX2Nhc2VzID0gbXBfZGVzWywgbXBfZGVzJGNvdmlkX2NvbmZpcm1lZCA9PSBUUlVFXQpjb3ZpZF9jb3VudHMgPSBjb3VudHMoY292aWRfY2FzZXMsIG5vcm1hbGl6ZWQgPSBUKQpjb3ZpZF9jb3VudHMgPSBjb3ZpZF9jb3VudHNbY292Ml9nZW5lcyRlbnNlbWJsX2dlbmVfaWQsIF0KCmNvdmlkX2NvdW50cyA9IGNvdmlkX2NvdW50cyAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImdlbmUiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAiMzQwMTk1MDQ2IjoiMzQwMjM5ODY3IiwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2FtcGxlIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIkNvdW50cyIpICU+JSAKICBsZWZ0X2pvaW4oLiwgbm9uX2h1bWFuX2dlbmVzLCBieSA9IGMoImdlbmUiID0gImVuc2VtYmxfZ2VuZV9pZCIpKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtYyhnZW5lLCB2aXJ1cykpICU+JSAKICBsZWZ0X2pvaW4oLiwgYXMuZGF0YS5mcmFtZShjb2xEYXRhKG1wX2RlcykpLCBieSA9ICJzYW1wbGUiKQoKZ2dwbG90KGNvdmlkX2NvdW50cywgYWVzKHggPSBkYXlfb2ZfaW50dWJhdGlvbiwgeSA9IENvdW50cykpICsKICBmYWNldF93cmFwKH4gZ2VuZV9uYW1lLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGKQpgYGAgICAKVW5mb3J0dW5hdGVseSB0aGlzIGlzIHNvbWV3aGF0IGJpbmFyaXplZC4gQmV0dGVyIHRvIHRyZWF0IGl0IGFzIHN1Y2guICAgCiAgIApgYGB7cn0KY292aWRfY291bnRzX2JpbmFyaXplZCA9IGNvdmlkX2NvdW50cyAlPiUgCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgCiAgbXV0YXRlKGFsbF92aXJhbF9jb3VudHMgPSBzdW0oQ291bnRzKSkgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlLCBhbGxfdmlyYWxfY291bnRzLCBkYXlfb2ZfaW50dWJhdGlvbikgJT4lIAogIHVuaXF1ZSgpICU+JSAKICBtdXRhdGUodmlydXNfZGV0ZWN0ZWQgPSBhbGxfdmlyYWxfY291bnRzID4gMCkKCmNvci50ZXN0KGNvdmlkX2NvdW50c19iaW5hcml6ZWQkYWxsX3ZpcmFsX2NvdW50cywgY292aWRfY291bnRzX2JpbmFyaXplZCRkYXlfb2ZfaW50dWJhdGlvbiwgbWV0aG9kID0gInNwZWFybWFuIikKCmdncGxvdChjb3ZpZF9jb3VudHNfYmluYXJpemVkLCBhZXMoeCA9IGRheV9vZl9pbnR1YmF0aW9uLCB5ID0gYWxsX3ZpcmFsX2NvdW50cykpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cyIikgKwogIGdlb21fc21vb3RoKHNlID0gRikKYGBgCgojIyBFeHBvcnQgZm9yIG1vZGVsaW5nIGNvcmUgICAKYGBge3IgZXZhbD1GQUxTRX0KY29sX3R5cGVzID0gdW5saXN0KGxhcHBseShtZXRhZGF0YSwgY2xhc3MpKQpsaXN0X2NvbHMgPSBuYW1lcyhjb2xfdHlwZXNbY29sX3R5cGVzID09ICJBc0lzIl0pCnNhZmVfbWV0YWRhdGEgPSBtZXRhZGF0YSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtYyhhbGxfb2YobGlzdF9jb2xzKSkpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkKd3JpdGUuY3N2KHNhZmVfbWV0YWRhdGEsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L1dvcmtzcGFjZS9DT1ZJRDE5X2JhbF9tcy8yMDA3MDlfYnVsa19tZXRhZGF0YS5jc3YiKQp3cml0ZS5jc3YoY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IEYpLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9Xb3Jrc3BhY2UvQ09WSUQxOV9iYWxfbXMvMjAwNzA5X2J1bGtfY291bnRzX3Jhdy5jc3YiKQp3cml0ZS5jc3YoY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IFQpLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9Xb3Jrc3BhY2UvQ09WSUQxOV9iYWxfbXMvMjAwNzA5X2J1bGtfY291bnRzX2Rlc2VxMl9ub3JtYWxpemVkLmNzdiIpCmBgYAogICAgICAKIyMgV2hpY2ggc2FtcGxlcyBhcmUgd29ydGggc2VxdWVuY2luZyBmdXJ0aGVyPyAgIAojIyMgRmlyc3QgYmF0Y2ggICAKYGBge3IgZXZhbD1GQUxTRX0KZ29vZF9zYW1wbGVzID0gbXBfZGVzWywgKCghaXMubmEobXBfZGVzJFJJTikgJiBtcF9kZXMkUklOID49IDcpICYgCiAgICAgICAgICAgICAgICAgICAgbXBfZGVzJFNUQVJfbXFjX2dlbmVyYWxzdGF0c19zdGFyX3VuaXF1ZWx5X21hcHBlZF9wZXJjZW50ID49IDMwICYKICAgICAgICAgICAgICAgICAgICBtcF9kZXMkZmVhdHVyZUNvdW50c19tcWNfZ2VuZXJhbHN0YXRzX2ZlYXR1cmVjb3VudHNfcGVyY2VudF9hc3NpZ25lZCA+PSAzMCkgJgogICAgICAgICAgICAgICAgICAgIG1wX2RlcyRSTkFfY29uY2VudHJhdGlvbl9wZ191bCA+PSAxMjUgfAogICAgICAgICAgICAgICAgICAgIChtcF9kZXMkaWF2X2gxbjFfZGV0ZWN0ZWQgPT0gVFJVRSB8IG1wX2RlcyRzYXJzX2NvdjJfZGV0ZWN0ZWQgPT0gVFJVRSldCgpzZWxlY3Rpb25fZGF0YSA9IGFzLmRhdGEuZnJhbWUoY29sRGF0YShnb29kX3NhbXBsZXMpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChzYW1wbGUsIHRjX3B0X3N0dWR5X2lkLCBSSU4sIFNUQVJfbXFjX2dlbmVyYWxzdGF0c19zdGFyX3VuaXF1ZWx5X21hcHBlZF9wZXJjZW50LAogICAgICAgICBmZWF0dXJlQ291bnRzX21xY19nZW5lcmFsc3RhdHNfZmVhdHVyZWNvdW50c19wZXJjZW50X2Fzc2lnbmVkLCBpYXZfaDFuMV9kZXRlY3RlZCwgCiAgICAgICAgIHNhcnNfY292Ml9kZXRlY3RlZCwgY292aWRfY29uZmlybWVkLCBiYXRjaCwgUk5BX2NvbmNlbnRyYXRpb25fcGdfdWwsIHBuYV90eXBlKQpzZWxlY3Rpb25fZGF0YQpgYGAgICAKS2VlcGVyczogICAKLSAzNDAyMjQ4MDggKElBVikKLSAzMDQwMTc1NTMgKElBViArIGxpa2VseSBhbm90aGVyIGNvcm9uYXZpcnVzKQotIDM0MDIzOTgwNSAoQ292MikKLSAzNDAyMzM4OTYgKENvdjIpCi0gMzQwMjM5NzkwIChDb3YyKQotIDM0MDIzOTc4OSAoQ292MikKLSAzMDQwMTI2OTkgKE90aGVyIC0tIGxpa2VseSBhbm90aGVyIGNvcm9uYXZpcnVzKQotIDMwMDMxMjM4OSAob3RoZXIpCi0gMzA0MDIwMzYyIChvdGhlcikKICAgCmBgYHtyIGV2YWw9RkFMU0V9CmtlZXBlcnMgPSBzZWxlY3Rpb25fZGF0YSAlPiUgCiAgZHBseXI6OmZpbHRlcihzYW1wbGUgJWluJSBjKDMwNDAyMDI5OCwgMzQwMjI0ODA4LCAzMDQwMTc1NTMsIDM0MDIzOTgwNSwgMzQwMjMzODk2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzNDAyMzk3OTAsIDM0MDIzOTc4OSwgMzA0MDEyNjk5LCAzMDAzMTIzODksIDMwNDAyMDM2MikpICU+JSAKICBtdXRhdGUodm9sX2Zvcl8yNTBfcGcgPSByb3VuZCgyNTAgLyBSTkFfY29uY2VudHJhdGlvbl9wZ191bCwgZGlnaXRzID0gMykpCmtlZXBlcnMkZGlsdXRpb24gPSBpZmVsc2Uoa2VlcGVycyR2b2xfZm9yXzI1MF9wZyA+IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gaWZlbHNlKGtlZXBlcnMkdm9sX2Zvcl8yNTBfcGcgPiAwLjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDIwKSkKa2VlcGVycyRkaWx1dGlvbl92b2xfZm9yXzI1MF9wZyA9IHJvdW5kKDI1MCAvIChrZWVwZXJzJFJOQV9jb25jZW50cmF0aW9uX3BnX3VsIC8ga2VlcGVycyRkaWx1dGlvbiksIGRpZ2l0cyA9IDMpCndyaXRlLmNzdihrZWVwZXJzLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNjEyX3Jlc2VxdWVuY2luZ19zYW1wbGVzLmNzdiIpCmtlZXBlcnMKYGBgICAgCiAgIAojIFNpZ25hdHVyZXMgYXNzb2NpYXRlZCB3aXRoIFNBUlMtQ29WLTIgICAKIyMgU2luZ2xlIGdlbmVzICAgCiMjIyBJTDYgICAKYGBge3J9CmlsNl9jb3VudHMgPSBwbG90Q291bnRzKG1wX2RlcywgCiAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMzYyNDQiLAogICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULAogICAgICAgICAgIGludGdyb3VwID0gImNvdmlkX2NvbmZpcm1lZCIsCiAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInNhbXBsZSIpICU+JSAKICBsZWZ0X2pvaW4oLiwgCiAgICAgICAgICAgIG1ldGFkYXRhLAogICAgICAgICAgICBieSA9IGMoInNhbXBsZSIsICJjb3ZpZF9jb25maXJtZWQiKSkKCmNvci50ZXN0KGlsNl9jb3VudHMkY291bnQsIGlsNl9jb3VudHMkcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoKQppbDZfcGxvdCA9IGdncGxvdChpbDZfY291bnRzLCBhZXMoeCA9IHBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCwgeSA9IGNvdW50LCBjb2xvciA9IGNvdmlkX2NvbmZpcm1lZCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICB5bGFiKCJJTDYgQ291bnRzIikKYGBgICAgCkxhdGVyIGNvbmZpcm1lZCBOU0QgYnkgZ3JvdXAuIENsZWFybHkgY29ycmVsYXRlcyB3aXRoIE1vQU0gY2hhcmFjdGVyLiAgICAgICAgCiAgIAojIyMgSUwxYiAgIApgYGB7cn0KaWwxYl9jb3VudHMgPSBwbG90Q291bnRzKG1wX2RlcywgCiAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMjU1MzgiLAogICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULAogICAgICAgICAgIGludGdyb3VwID0gImNvdmlkX2NvbmZpcm1lZCIsCiAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInNhbXBsZSIpICU+JSAKICBsZWZ0X2pvaW4oLiwgCiAgICAgICAgICAgIG1ldGFkYXRhLAogICAgICAgICAgICBieSA9IGMoInNhbXBsZSIsICJjb3ZpZF9jb25maXJtZWQiKSkKCmNvci50ZXN0KGlsMWJfY291bnRzJGNvdW50LCBpbDFiX2NvdW50cyRwZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2gpCmlsMWJfcGxvdCA9IGdncGxvdChpbDFiX2NvdW50cywgYWVzKHggPSBwZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2gsIHkgPSBjb3VudCwgY29sb3IgPSBjb3ZpZF9jb25maXJtZWQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIHNjYWxlX3lfbG9nMTAoKSArIAogIHlsYWIoIklMMWIgQ291bnRzIikKCmlsNl9wbG90IC8gaWwxYl9wbG90CmBgYApMYXRlciBjb25maXJtZWQgc2lnbmlmaWNhbnRseSBkb3ducmVndWxhdGVkLCBhY3R1YWxseS4gICAKCiMjIEJhc2ljIERFQSAgIAojIyMgR2VuZSBoaXRzICAgCiAgIApWZXJzdXMgaGVhbHRoeSBjb250cm9scyAgIApgYGB7cn0KY292Ml92c19oY19yZXN1bHRzID0gYXMuZGF0YS5mcmFtZShyZXN1bHRzKG9iamVjdCA9IG1wX2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygiRGlhZ25vc2lzIiwgIkNPVklEXzE5IiwgIkhlYWx0aHlfQ29udHJvbCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBUKSkKCmNvdjJfdnNfaGNfcmVzdWx0c19pZHMgPSBjb3YyX3ZzX2hjX3Jlc3VsdHMgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogIGxlZnRfam9pbiguLCBnZW5lX2NvbnYpICU+JSAKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCAwLjA1IHwgIWdyZXBsKCJFTlNHIiwgZW5zZW1ibF9nZW5lX2lkKSkgJT4lIAogIGFycmFuZ2UobG9nMkZvbGRDaGFuZ2UpCgp3cml0ZS5jc3YoY292Ml92c19oY19yZXN1bHRzX2lkcywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcxN19zdGFuZGFyZF9ERUFfY292aWRfb3Zlcl9oZWFsdGh5Y29udHJvbHMuY3N2IikKCmNvdjJfdnNfaGNfcmVzdWx0c19pZHMKYGBgICAgCiAgIApVcHJlZ3VsYXRpb24gb2YgQ29WLTIgZ2VuZXMgaXMgZ29yZ2VvdXMKICAgClZlcnN1cyBub24tcG5hIChzaWNrKSBjb250cm9scwpgYGB7cn0KY292Ml92c19ucGNfcmVzdWx0cyA9IGFzLmRhdGEuZnJhbWUocmVzdWx0cyhvYmplY3QgPSBtcF9kZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoIkRpYWdub3NpcyIsICJDT1ZJRF8xOSIsICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsID0gVCkpCgpjb3YyX3ZzX25wY19yZXN1bHRzX2lkcyA9IGNvdjJfdnNfbnBjX3Jlc3VsdHMgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogIGxlZnRfam9pbiguLCBnZW5lX2NvbnYpICU+JSAKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCAwLjA1IHwgIWdyZXBsKCJFTlNHIiwgZW5zZW1ibF9nZW5lX2lkKSkgJT4lIAogIGFycmFuZ2UobG9nMkZvbGRDaGFuZ2UpCgp3cml0ZS5jc3YoY292Ml92c19ucGNfcmVzdWx0c19pZHMsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MTdfc3RhbmRhcmRfREVBX2NvdmlkX292ZXJfbm9ucG5ldW1vbmlhY29udHJvbHMuY3N2IikKCmNvdjJfdnNfbnBjX3Jlc3VsdHNfaWRzCmBgYAogICAKVmVyc3VzIG90aGVyIHZpcmFsIFBOQQpgYGB7cn0KY292Ml92c19vdnBfcmVzdWx0cyA9IGFzLmRhdGEuZnJhbWUocmVzdWx0cyhvYmplY3QgPSBtcF9kZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoIkRpYWdub3NpcyIsICJDT1ZJRF8xOSIsICJPdGhlcl9WaXJhbF9QbmV1bW9uaWEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsID0gVCkpCgpjb3YyX3ZzX292cF9yZXN1bHRzX2lkcyA9IGNvdjJfdnNfb3ZwX3Jlc3VsdHMgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogIGxlZnRfam9pbiguLCBnZW5lX2NvbnYpICU+JSAKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCAwLjA1IHwgIWdyZXBsKCJFTlNHIiwgZW5zZW1ibF9nZW5lX2lkKSkgJT4lIAogIGFycmFuZ2UobG9nMkZvbGRDaGFuZ2UpCgpjb3YyX3ZzX292cF9yZXN1bHRzX2lkcwoKd3JpdGUuY3N2KGNvdjJfdnNfb3ZwX3Jlc3VsdHNfaWRzLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzE3X3N0YW5kYXJkX0RFQV9jb3ZpZF9vdmVyX290aGVydmlyYWxwbmV1bW9uaWEuY3N2IikKYGBgICAgCiAgIApWZXJzdXMgb3RoZXIgUE5BCmBgYHtyfQpjb3YyX3ZzX290aGVyX3BuYV9yZXN1bHRzID0gYXMuZGF0YS5mcmFtZShyZXN1bHRzKG9iamVjdCA9IG1wX2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygiRGlhZ25vc2lzIiwgIkNPVklEXzE5IiwgIk90aGVyX1BuZXVtb25pYSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBUKSkKCmNvdjJfdnNfb3RoZXJfcG5hX3Jlc3VsdHNfaWRzID0gY292Ml92c19vdGhlcl9wbmFfcmVzdWx0cyAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgbGVmdF9qb2luKC4sIGdlbmVfY29udikgJT4lIAogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IDAuMDUgfCAhZ3JlcGwoIkVOU0ciLCBlbnNlbWJsX2dlbmVfaWQpKSAlPiUgCiAgYXJyYW5nZShsb2cyRm9sZENoYW5nZSkKCndyaXRlLmNzdihjb3YyX3ZzX290aGVyX3BuYV9yZXN1bHRzX2lkcywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcxN19zdGFuZGFyZF9ERUFfY292aWRfb3Zlcl9vdGhlcnBuZXVtb25pYS5jc3YiKQoKY292Ml92c19vdGhlcl9wbmFfcmVzdWx0c19pZHMKYGBgICAKICAgCiMjIyBNQSBQbG90ICAgCmBgYHtyIGV2YWw9RkFMU0V9CnByZXR0eV9NQV9wbG90KGNvdjJfdnNfb3ZwX3Jlc3VsdHMsIGN1c3RvbV9hbm5vdGF0aW9uID0gIGdlbmVfY29udikKYGBgCgogICAKIyMjIEhlYXRtYXAgICAKICAgCkhvdyBtYW55IGNsdXN0ZXJzIGRvZXMgaXQgdGFrZT8gICAKYGBge3J9CmVsYm93ID0ga19lbGJvdyhkZ2UgPSBtcF9kZXMsIGRlc2lnbiA9ICJ+RGlhZ25vc2lzIiwgCiAgICAgICAgY29yZXMgPSAxMiwgCiAgICAgICAgbWluUmVwcyA9IEluZiwKICAgICAgICByYW5kb21fc2VlZCA9IDEyMzQ1LAogICAgICAgIG1heF9rID0gMjUsCiAgICAgICAgcXZhbF9jdXRvZmYgPSAwLjAxKQplbGJvdwpgYGAgICAKNSBzZWVtcyBmYWlyLiAgIAogICAgCmBgYHtyfQppbnR1YmF0aW9uX3BhbCA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJQdXJwbGVzIilbMzo5XSkobWF4KG1wX2RlcyRmaW5pdGVfZGF5X29mX2ludHViYXRpb24sIG5hLnJtID0gVCkgKyAxKQppbnR1YmF0aW9uX3BhbFsxOjNdID0gcmVwKCIjMDAwMDAwIiwzKSAjaGlnaGxpZ2h0ICJEMCIKCmNvdjJfa21lYW5zX25vY2x1c3RlcmluZyA9IGtfbWVhbnNfZmlndXJlKGRnZSA9IG1wX2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gIn5EaWFnbm9zaXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29fYW5ub3RhdGlvbnMgPSAib3JnLkhzLmVnLmRiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5zZW1ibF9kYiA9ICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmRfZmFjdG9ycyA9IGMoIkRpYWdub3NpcyIsICJmaW5pdGVfZGF5X29mX2ludHViYXRpb24iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0yLCAyLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluUmVwcyA9IEluZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5fZ2VuZXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlfZ29fdGVybXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl9nb190ZXJtcyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlTWVhbkN1dG9mZiA9IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbV9zZWVkID0gMTIzNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXZhbF9jdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gbGlzdChEaWFnbm9zaXMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gZmlnMl9wYWxbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIgPSBmaWcyX3BhbFsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSURfMTkiID0gZmlnMl9wYWxbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9WaXJhbF9QbmV1bW9uaWEiID0gZmlnMl9wYWxbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1BuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiA9ICBpbnR1YmF0aW9uX3BhbCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9vcmRlciA9IGMoMywgNSwgMSwgMiwgNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvcnRDb2x1bW5zID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fc29ydF9mYWN0b3JzID0gYygiRGlhZ25vc2lzIiwgImRheTBfc2FtcGxlIikpCgpjb3YyX2ttZWFuc19jbHVzdGVyZWQgPSBrX21lYW5zX2ZpZ3VyZShkZ2UgPSBtcF9kZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9ICJ+RGlhZ25vc2lzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvX2Fubm90YXRpb25zID0gIm9yZy5Icy5lZy5kYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuc2VtYmxfZGIgPSAiaHNhcGllbnNfZ2VuZV9lbnNlbWJsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2ZhY3RvcnMgPSBjKCJEaWFnbm9zaXMiLCAiZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMiwgMiwgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pblJlcHMgPSBJbmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuX2dlbmVzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X2dvX3Rlcm1zID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5fZ29fdGVybXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3duYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZU1lYW5DdXRvZmYgPSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb21fc2VlZCA9IDEyMzQ1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF2YWxfY3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoRGlhZ25vc2lzID0gYygiSGVhbHRoeV9Db250cm9sIiA9IGZpZzJfcGFsWzZdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklEXzE5IiA9IGZpZzJfcGFsWzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfVmlyYWxfUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9QbmV1bW9uaWEiID0gZmlnMl9wYWxbNF0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaW5pdGVfZGF5X29mX2ludHViYXRpb24gPSAgaW50dWJhdGlvbl9wYWwpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXN0b21fb3JkZXIgPSBjKDMsIDUsIDEsIDIsIDQpKQpmb3IoaSBpbiAxOmxlbmd0aChjb3YyX2ttZWFuc19jbHVzdGVyZWQkR08pKQp7CiAgY292Ml9rbWVhbnNfY2x1c3RlcmVkJEdPW1tpXV0kY2x1c3RlciA9IGkKfQpjb3YyX2ttZWFuc19jbHVzdGVyZWQkZ29fZGYgPSBiaW5kX3Jvd3MoY292Ml9rbWVhbnNfY2x1c3RlcmVkJEdPKSAlPiUgCiAgYXJyYW5nZShjbHVzdGVyLCBwYWRqKQpzYXZlUkRTKGNvdjJfa21lYW5zX2NsdXN0ZXJlZCwgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9rX21lYW5zX2NsdXN0ZXJlZC5yZHMiKQp3cml0ZS5jc3YoY292Ml9rbWVhbnNfY2x1c3RlcmVkJGdlbmVzLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzIxX2tfbWVhbnNfZ2VuZXMuY3N2IikKd3JpdGUuY3N2KGNvdjJfa21lYW5zX2NsdXN0ZXJlZCRnb19kZiwgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9rX21lYW5zX0dPLmNzdiIpCmBgYCAgIAogICAKVGhpcyBpcyBhY3R1YWxseSB2ZXJ5IGNvb2wgKGFuZCBuaWNlbHkgZm9yZXNoYWRvd3MgdGhlIGxhdGVyIFdHQ05BIHJlc3VsdHMpLiBDMTogbW9zdGx5IENPVklELXJlbGF0ZWQoISk7IGhpZ2hseSBlbnJpY2hlZCBmb3IgdHlwZSBJIGludGVyZmVyb24gcmVzcG9uc2UgKG5vdCBwcm9kdWN0aW9uIHNvIG11Y2gpLCBhcyB3ZWxsIGFzIE1IQy1JLiBDMjogbW9zdGx5IG5vbnZpcmFsIHBuZXVtb25pYXMuIFByZXR0eSBjbGFzc2ljIFNUQVQzIGluZmxhbW1hdG9yeSByZXNwb25zZS4gCiAgIAojIyMgRDAgSGVhdG1hcCAgIApgYGB7ciBldmFsPUZBTFNFfQpkMF9kZXMgPSBtcF9kZXNbLCAhaXMubmEobXBfZGVzJGRheV9vZl9pbnR1YmF0aW9uKSAmIG1wX2RlcyRkYXlfb2ZfaW50dWJhdGlvbiA8PSAyICYgbXBfZGVzJGRheV9vZl9pbnR1YmF0aW9uID49IDBdCiMgY292Ml9kMF9rbWVhbnNfbm9jbHVzdGVyaW5nID0ga19tZWFuc19maWd1cmUoZGdlID0gZDBfZGVzLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSAifkRpYWdub3NpcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IDMsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29fYW5ub3RhdGlvbnMgPSAib3JnLkhzLmVnLmRiIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnNlbWJsX2RiID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2ZhY3RvcnMgPSBjKCJEaWFnbm9zaXMiLCAicGVyY2VudF90b3RhbF9DRDIwNl9oaWdoIiksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSAxMiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pblJlcHMgPSBJbmYsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5fZ2VuZXMgPSBULAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheV9nb190ZXJtcyA9IEYsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5fZ29fdGVybXMgPSBULAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2ZvbnRzaXplID0gMiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbUFubm8gPSBnZW5lX2NvbnYsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vSm9pbkNvbCA9ICJlbnNlbWJsX2dlbmVfaWQiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc29ydENvbHVtbnMgPSBULAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sU29ydEZhY3RvciA9ICJEaWFnbm9zaXMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZU1lYW5DdXRvZmYgPSAyMCkKCmNvdjJfZDBfa21lYW5zX2NsdXN0ZXJlZCA9IGtfbWVhbnNfZmlndXJlKGRnZSA9IGQwX2RlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9ICJ+RGlhZ25vc2lzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvX2Fubm90YXRpb25zID0gIm9yZy5Icy5lZy5kYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuc2VtYmxfZGIgPSAiaHNhcGllbnNfZ2VuZV9lbnNlbWJsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2ZhY3RvcnMgPSBjKCJEaWFnbm9zaXMiLCAicGVyY2VudF90b3RhbF9DRDIwNl9oaWdoIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMywgMywgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pblJlcHMgPSBJbmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuX2dlbmVzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X2dvX3Rlcm1zID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5fZ29fdGVybXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfZm9udHNpemUgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbUFubm8gPSBnZW5lX2NvbnYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub0pvaW5Db2wgPSAiZW5zZW1ibF9nZW5lX2lkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlTWVhbkN1dG9mZiA9IDIwKQpgYGAKICAgCiMjIEluZGl2aWR1YWwgZ2VuZXMgICAKIyMjIENDTDI0ICAgClRoaXMgd2FzIGFuIGludGVyZXN0aW5nIENPVklELXNwZWNpZmljIGhpdC4gQWNjb3JkaW5nIHRvIHB1Ymxpc2hlZCBkYXRhLCBpdCBpcyBhIGhpZ2hseSBzZWxlY3RpdmUgY2hlbW9hdHRyYWN0YW50IGZvciBUIGNlbGxzLiBXb3VsZCBleHBlY3QgdGhhdCBpdCBzaG91bGQgY29ycmVsYXRlIHdpdGggVCBjZWxsIGFidW5kYW5jZS4gICAKICAgCmBgYHtyfQpjY2wyNF9jb3VudHMgPSBwbG90Q291bnRzKG1wX2RlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMDYxNzgiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gIkRpYWdub3NpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZCA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgcGMgPSBULAogICAgICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUKQpnZ3Bsb3QoY2NsMjRfY291bnRzLCBhZXMoeCA9IERpYWdub3NpcywgeSA9IGNvdW50LCBmaWxsICA9IERpYWdub3NpcykpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjUsIG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21faml0dGVyKHNpemUgPSAwLjEsIHdpZHRoID0gMC4yNSkgKwogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIiIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiSGVhbHRoeV9Db250cm9sIiA9IGZpZzJfcGFsWzZdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIgPSBmaWcyX3BhbFsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDT1ZJRF8xOSIgPSBmaWcyX3BhbFsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9WaXJhbF9QbmV1bW9uaWEiID0gZmlnMl9wYWxbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzRdKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiSGVhbHRoeV9Db250cm9sIiA9ICJIZWFsdGh5XG5Db250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiID0gIk5vbi1QbmV1bW9uaWFcbkNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklEXzE5IiA9ICJDT1ZJRC0xOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfVmlyYWxfUG5ldW1vbmlhIiA9ICJPdGhlciBWaXJhbFxuUG5ldW1vbmlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9QbmV1bW9uaWEiID0gIk90aGVyXG5QbmV1bW9uaWEiKSkgKwogIHhsYWIoIiIpICsKICB5bGFiKCJDQ0wyNCBDb3VudHMiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiwgZmFtaWx5ID0gIkFyaWFsIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoKICAgCmBgYHtyfQpjY2wyNF9jZDQgPSBwbG90Q291bnRzKG1wX2RlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMDYxNzgiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gInBlcmNlbnRfQ0Q0X3RvdGFsIiwKICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkID0gVCwKICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlIikKY2NsMjRfY2Q4ID0gcGxvdENvdW50cyhtcF9kZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgPSAiRU5TRzAwMDAwMTA2MTc4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRncm91cCA9ICJwZXJjZW50X0NEOF90b3RhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZCA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oInNhbXBsZSIpCmNjbDI0X3RjZWxscyA9IGxlZnRfam9pbihjY2wyNF9jZDQsIGNjbDI0X2NkOCkgJT4lIAogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJmbG93X3BhcmFtZXRlciIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicGVyY2VudCIsCiAgICAgICAgICAgICAgIGNvbHMgPSBjKHBlcmNlbnRfQ0Q4X3RvdGFsLCBwZXJjZW50X0NENF90b3RhbCkpCgpnZ3Bsb3QoY2NsMjRfdGNlbGxzLCBhZXMoeCA9IGNvdW50LCB5ID0gcGVyY2VudCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICBmYWNldF93cmFwKH5mbG93X3BhcmFtZXRlcikgKwogIHNjYWxlX3hfbG9nMTAoKQpgYGAKUHJldHR5IHBvb3IgY29ycmVsYXRpb24gICAKICAgCiMjIElMLTYgICAKYGBge3J9CmlsNl9jb3VudHMgPSBwbG90Q291bnRzKG1wX2RlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMzYyNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gIkRpYWdub3NpcyIsCiAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZCA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgcGMgPSBULAogICAgICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUKQpnZ3Bsb3QoaWw2X2NvdW50cywgYWVzKHggPSBEaWFnbm9zaXMsIHkgPSBjb3VudCwgZmlsbCAgPSBEaWFnbm9zaXMpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC41LCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX2ppdHRlcihzaXplID0gMC4xLCB3aWR0aCA9IDAuMjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMTAiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICIiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSBmaWcyX3BhbFs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb25fUG5ldW1vbmlhX0NvbnRyb2wiID0gZmlnMl9wYWxbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSURfMTkiID0gZmlnMl9wYWxbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfVmlyYWxfUG5ldW1vbmlhIiA9IGZpZzJfcGFsWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1BuZXVtb25pYSIgPSBmaWcyX3BhbFs0XSkpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkhlYWx0aHlfQ29udHJvbCIgPSAiSGVhbHRoeVxuQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uX1BuZXVtb25pYV9Db250cm9sIiA9ICJOb24tUG5ldW1vbmlhXG5Db250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDT1ZJRF8xOSIgPSAiQ09WSUQtMTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIgPSAiT3RoZXIgVmlyYWxcblBuZXVtb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXJfUG5ldW1vbmlhIiA9ICJPdGhlclxuUG5ldW1vbmlhIikpICsKICB4bGFiKCIiKSArCiAgeWxhYigiSUwtNiBDb3VudHMiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiwgZmFtaWx5ID0gIkFyaWFsIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoKIyMgU2FzaGEncyBwaWNrcyAgIAojIyMgQWxsIHRvIHN0YXJ0ICAgCmBgYHtyfQpzYXNoYV9nZW5lcyA9IGMoIkNDTDIwIiwgIkNDTDI0IiwgIkNDTDMiLCAiQ0NMOCIsICJDQ1IyIiwgIkNDTDIiLCAiSUwxQSIsICJJTDFCIiwgIkFSRUciLCAKICAgICAgICAgICAgICAgICJDWENSNCIsICJUTkZTRjE0IiwgIkNYQ0wzIiwgIkNYQ0w1IiwgIkNYQ0wxIiwgIkNYQ0w4IiwgIkFURjQiLCAiQ0QxNjQiLCAKICAgICAgICAgICAgICAgICJNRkdFOCIsICJJTDEzUkExIiwgIklMMVJMMSIsICJJTDE4UjEiLCAiVlNJRzQiLCAiVkVHRkEiLCAiRERJVDQiLCAiQkFHMyIsIAogICAgICAgICAgICAgICAgIkROQUpCMSIsICJIU1A5MEFBNlAiLCAiSFNQQTFCIiwgIkhTUEExQSIpCnNhc2hhX2dlbmVzID0gc3Vic2V0KGdlbmVfY29udiwgZ2VuZV9uYW1lICVpbiUgc2FzaGFfZ2VuZXMpCgpzYXNoYV9jb3VudHMgPSBtY2xhcHBseShzYXNoYV9nZW5lcyRlbnNlbWJsX2dlbmVfaWQsIGZ1bmN0aW9uKHgpewogIGNvdW50cyA9IHBsb3RDb3VudHMobXBfZGVzLAogICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IHgsCiAgICAgICAgICAgICAgICAgICAgICBpbnRncm91cCA9ICJEaWFnbm9zaXMiLAogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGF0YSA9IFQsCiAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkID0gVCwKICAgICAgICAgICAgICAgICAgICAgIHBjID0gVCkKICBjb3VudHMkZ2VuZSA9IHgKICByZXR1cm4oY291bnRzKX0pCnNhc2hhX2NvdW50cyA9IGJpbmRfcm93cyhzYXNoYV9jb3VudHMpICU+JSAKICBsZWZ0X2pvaW4oLiwgc2FzaGFfZ2VuZXMsIGJ5ID0gYygiZ2VuZSIgPSAiZW5zZW1ibF9nZW5lX2lkIikpCgpzYXNoYV9nZW5lX3Bsb3QgPSBnZ3Bsb3Qoc2FzaGFfY291bnRzLCBhZXMoeCA9IERpYWdub3NpcywgeSA9IGNvdW50LCBmaWxsID0gRGlhZ25vc2lzKSkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuNSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9qaXR0ZXIoc2l6ZSA9IDAuMSwgd2lkdGggPSAwLjI1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gZmlnMl9wYWxbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uX1BuZXVtb25pYV9Db250cm9sIiA9IGZpZzJfcGFsWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklEXzE5IiA9IGZpZzJfcGFsWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIgPSBmaWcyX3BhbFszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9QbmV1bW9uaWEiID0gZmlnMl9wYWxbNF0pKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gIkhlYWx0aHlcbkNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbl9QbmV1bW9uaWFfQ29udHJvbCIgPSAiTm9uLVBuZXVtb25pYVxuQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09WSURfMTkiID0gIkNPVklELTE5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlcl9WaXJhbF9QbmV1bW9uaWEiID0gIk90aGVyIFZpcmFsXG5QbmV1bW9uaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyX1BuZXVtb25pYSIgPSAiT3RoZXJcblBuZXVtb25pYSIpKSArCiAgeGxhYigiIikgKwogIHlsYWIoIkdlbmUgQ291bnRzIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGZhY2V0X3dyYXAofmdlbmVfbmFtZSkKc2FzaGFfZ2VuZV9wbG90CmBgYAoKICAgCiMgQ29tcGFyZSB3aXRoIHNvcnQgZGF0YSAgIAojIyBTdWJzZXQgdG8gc2FtcGxlcyB3aXRoIHNvcnRpbmcgZGF0YSAgIApgYGB7cn0Kc29ydGVkID0gbXBbLCAhaXMubmEobXAkcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoKV0KZGVzaWduKHNvcnRlZCkgPSB+RGlhZ25vc2lzICsgcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoCmBgYCAgIAogICAKIyMgRGV0ZXJtaW5lIGJlc3QgZGlzcGVyc2lvbiBlc3RpbWF0ZXMgICAKIyMjIFBhcmFtZXRyaWMgICAKYGBge3J9CnNvcnRlZF9kZXNfcGFyYW1ldHJpYyA9IERFU2VxKHNvcnRlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZml0VHlwZSA9ICJwYXJhbWV0cmljIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFQpICNubyBvdXRsaWVycyBpbiB0aGlzIGNhc2UKcGxvdERpc3BFc3RzKHNvcnRlZF9kZXNfcGFyYW1ldHJpYykKYGBgICAgCkFjdHVhbGx5IHZlcnkgZGVjZW50ICAgICAgCiAgICAKIyMjIExvY2FsCmBgYHtyfQpzb3J0ZWRfZGVzX2xvY2FsID0gREVTZXEoc29ydGVkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBmaXRUeXBlID0gImxvY2FsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFQpCnBsb3REaXNwRXN0cyhzb3J0ZWRfZGVzX2xvY2FsKQpzb3J0ZWRfZGVzID0gc29ydGVkX2Rlc19sb2NhbCAKcm0oc29ydGVkX2Rlc19sb2NhbCwgc29ydGVkX2Rlc19wYXJhbWV0cmljKQpgYGAgIApCb3RoIGhhdmUgdGhlaXIgaXNzdWVzIGJ1dCB0aGlzIGF0IGxlYXN0IGRvZXMgbm90IHRocm93IG91dCBsb3ctZXhwcmVzc2lvbiBnZW5lcyBmb3IgaGF2aW5nIGluZmluaXRlIGRpc3BlcnNpb24uICAgCiAgIAojIyBQQ0EgICAKYGBge3J9CnBjYV9kYXRhID0gcGxvdFBDQSh2c3Qoc29ydGVkKSwKICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygiY292aWRfY29uZmlybWVkIiksCiAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCkKcGNhX2RhdGEgPSBsZWZ0X2pvaW4ocGNhX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoY29sRGF0YShtcCkpLAogICAgICAgICAgICAgICAgICAgICBieSA9IGMoIm5hbWUiID0gInNhbXBsZSIsICJjb3ZpZF9jb25maXJtZWQiKSkKZ2dwbG90KHBjYV9kYXRhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgc2hhcGUgPSBjb3ZpZF9jb25maXJtZWQsIGNvbG9yID0gcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpCmBgYAogICAKIyMgQ2x1c3RlcmluZyAgIAojIyMgQWxsIHNhbXBsZXMgICAKYGBge3J9CmRldGVjdGlvbl9yYXRlID0gZnVuY3Rpb24oeCkKewogIHJldHVybihzdW0oeCA+IDApIC8gbGVuZ3RoKHgpKSAKfQoKYWxsX2NvdW50cyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBUKQojZ2V0IDUwMCBtb3N0IHZhcmlhYmxlIGdlbmVzIHdpdGggPiAxMCUgZGV0ZWN0aW9uCnJ2ID0gcm93VmFycyhhbGxfY291bnRzKQpwcm9wX2RldGVjdGVkID0gYXBwbHkoWCA9IGFsbF9jb3VudHMsIE1BUkdJTiA9IDEsIEZVTiA9IGRldGVjdGlvbl9yYXRlKQpzZWxlY3Rpb25fY3JpdGVyaWEgPSBkYXRhLmZyYW1lKHNhbXBsZSA9IHJvd25hbWVzKGFsbF9jb3VudHMpLCB2YXIgPSBydiwgcHJvcF9kZXRlY3RlZCA9IHByb3BfZGV0ZWN0ZWQpICU+JSAKICBmaWx0ZXIocHJvcF9kZXRlY3RlZCA+PSAwLjEgJiB2YXIgPiAwKSAlPiUgCiAgYXJyYW5nZShkZXNjKHZhcikpCnRvcF9nZW5lcyA9IGFzLmNoYXJhY3RlcihzZWxlY3Rpb25fY3JpdGVyaWEkc2FtcGxlWzE6MTAwMF0pCnRvcF9hbGxfY291bnRzID0gYWxsX2NvdW50c1t0b3BfZ2VuZXMsIF0KCmFubm90YXRpb24gPSBjb2xEYXRhKG1wX2RlcykgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjb3ZpZF9jb25maXJtZWQsIAogICAgICAgICAgICAgICAgc2Fyc19jb3YyX2RldGVjdGVkLAogICAgICAgICAgICAgICAgc2V4LAogICAgICAgICAgICAgICAgI2RheV9vZl9pbnR1YmF0aW9uLAogICAgICAgICAgICAgICAgaW5mZWN0aW9uX3R5cGUsCiAgICAgICAgICAgICAgICBwZXJjZW50X25ldXRyb3BoaWxzLAogICAgICAgICAgICAgICAgcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoKQpnZW5lX2Fubm90YXRpb24gPSBnZW5lX2NvbnYgJT4lIAogIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXModG9wX2FsbF9jb3VudHMpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJlbnNlbWJsX2dlbmVfaWQiKQoKcGhlYXRtYXAodG9wX2FsbF9jb3VudHMsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFQsCiAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRDIiLAogICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm90YXRpb24sCiAgICAgICAgIGxhYmVsc19yb3cgPSBnZW5lX2Fubm90YXRpb24kZ2VuZV9uYW1lLAogICAgICAgICBzY2FsZSA9ICJyb3ciLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVCwKICAgICAgICAgZm9udHNpemVfcm93ID0gMiwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsCiAgICAgICAgIGJyZWFrcyA9IHNlcSgtMywgMywgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPSAiUmRCdSIpKSkoMTAwKSwKICAgICAgICAgYW5nbGVfY29sID0gNDUpCmBgYAoKIyMjIERheSAwICAgCmBgYHtyfQpkYXkwX3NhbXBsZXMgPSB3aGljaChtcCRkYXlfb2ZfaW50dWJhdGlvbiA8PSAyKQpkYXkwID0gbXBfZGVzWywgZGF5MF9zYW1wbGVzXQpkYXkwX2NvdW50cyA9IGNvdW50cyhkYXkwLCBub3JtYWxpemVkID0gVCkKCiNnZXQgMTAwMCBtb3N0IHZhcmlhYmxlIGdlbmVzCnJ2ID0gcm93VmFycyhkYXkwX2NvdW50cykKcHJvcF9kZXRlY3RlZCA9IGFwcGx5KFggPSBkYXkwX2NvdW50cywgTUFSR0lOID0gMSwgRlVOID0gZGV0ZWN0aW9uX3JhdGUpCnNlbGVjdGlvbl9jcml0ZXJpYSA9IGRhdGEuZnJhbWUoc2FtcGxlID0gcm93bmFtZXMoZGF5MF9jb3VudHMpLCB2YXIgPSBydiwgcHJvcF9kZXRlY3RlZCA9IHByb3BfZGV0ZWN0ZWQpICU+JSAKICBmaWx0ZXIocHJvcF9kZXRlY3RlZCA+PSAwLjEgJiB2YXIgPiAwKSAlPiUgCiAgYXJyYW5nZShkZXNjKHZhcikpCnRvcF9nZW5lcyA9IGFzLmNoYXJhY3RlcihzZWxlY3Rpb25fY3JpdGVyaWEkc2FtcGxlWzE6MTAwMF0pCnRvcF9kYXkwX2NvdW50cyA9IGRheTBfY291bnRzW3RvcF9nZW5lcywgXQoKYW5ub3RhdGlvbiA9IGNvbERhdGEoZGF5MCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjb3ZpZF9jb25maXJtZWQsIAogICAgICAgICAgICAgICAgc2Fyc19jb3YyX2RldGVjdGVkLAogICAgICAgICAgICAgICAgZ2VuZGVyLAogICAgICAgICAgICAgICAgaW5mZWN0aW9uX3R5cGUsCiAgICAgICAgICAgICAgICBwZXJjZW50X25ldXRyb3BoaWxzLAogICAgICAgICAgICAgICAgcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoKQpnZW5lX2Fubm90YXRpb24gPSBnZW5lX2NvbnYgJT4lIAogIGRwbHlyOjpmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXModG9wX2RheTBfY291bnRzKSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiZW5zZW1ibF9nZW5lX2lkIikKCnBoZWF0bWFwKHRvcF9kYXkwX2NvdW50cywKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgIGFubm90YXRpb25fY29sID0gYW5ub3RhdGlvbiwKICAgICAgICAgbGFiZWxzX3JvdyA9IGdlbmVfYW5ub3RhdGlvbiRnZW5lX25hbWUsCiAgICAgICAgIHNjYWxlID0gInJvdyIsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBULAogICAgICAgICBzaG93X2NvbG5hbWVzID0gRiwKICAgICAgICAgZm9udHNpemVfcm93ID0gMiwKICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9ICJSZEJ1IikpKSgxMDApLAogICAgICAgICBhbmdsZV9jb2wgPSA0NSkKYGBgCgogICAKIyMgREVBICAgClZlcnN1cyBjb250cm9scwpgYGB7cn0KY292Ml92c19ucGNfcmVzdWx0cyA9IGFzLmRhdGEuZnJhbWUocmVzdWx0cyhvYmplY3QgPSBzb3J0ZWRfZGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKCJEaWFnbm9zaXMiLCAiQ09WSURfMTkiLCAiTm9uX1BuZXVtb25pYV9Db250cm9sIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbCA9IFQpKQoKY292Ml92c19ucGNfcmVzdWx0c19pZHMgPSBjb3YyX3ZzX25wY19yZXN1bHRzICU+JSAKICByb3duYW1lc190b19jb2x1bW4oImVuc2VtYmxfZ2VuZV9pZCIpICU+JSAKICBsZWZ0X2pvaW4oLiwgZ2VuZV9jb252KSAlPiUgCiAgZHBseXI6OmZpbHRlcihwYWRqIDwgMC4wNSB8ICFncmVwbCgiRU5TRyIsIGVuc2VtYmxfZ2VuZV9pZCkpCgp3cml0ZS5jc3YoY292Ml92c19ucGNfcmVzdWx0c19pZHMsICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MDJfc29ydGVkX0RFQV9jb3ZpZF9vdmVyX25vbnBuZXVtb25pYWNvbnRyb2xzLmNzdiIpCgpjb3YyX3ZzX25wY19yZXN1bHRzX2lkcwpgYGAKICAgClZlcnN1cyBvdGhlciB2aXJhbCBQTkEKYGBge3J9CmNvdjJfdnNfb3ZwX3Jlc3VsdHMgPSBhcy5kYXRhLmZyYW1lKHJlc3VsdHMob2JqZWN0ID0gc29ydGVkX2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygiRGlhZ25vc2lzIiwgIkNPVklEXzE5IiwgIk90aGVyX1ZpcmFsX1BuZXVtb25pYSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBUKSkKCmNvdjJfdnNfb3ZwX3Jlc3VsdHNfaWRzID0gY292Ml92c19vdnBfcmVzdWx0cyAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJlbnNlbWJsX2dlbmVfaWQiKSAlPiUgCiAgbGVmdF9qb2luKC4sIGdlbmVfY29udikgJT4lIAogIGRwbHlyOjpmaWx0ZXIocGFkaiA8IDAuMDUgfCAhZ3JlcGwoIkVOU0ciLCBlbnNlbWJsX2dlbmVfaWQpKQoKd3JpdGUuY3N2KGNvdjJfdnNfb3ZwX3Jlc3VsdHNfaWRzLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzAyX3NvcnRlZF9ERUFfY292aWRfb3Zlcl9vdGhlcnZpcmFscG5ldW1vbmlhLmNzdiIpCgpjb3YyX3ZzX25wY19yZXN1bHRzX2lkcwpgYGAgICAKICAgCmBgYHtyfQpjb3YyX3ZzX290aGVyX3BuYV9yZXN1bHRzID0gYXMuZGF0YS5mcmFtZShyZXN1bHRzKG9iamVjdCA9IHNvcnRlZF9kZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoIkRpYWdub3NpcyIsICJDT1ZJRF8xOSIsICJPdGhlcl9QbmV1bW9uaWEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsID0gVCkpCgpjb3YyX3ZzX290aGVyX3BuYV9yZXN1bHRzX2lkcyA9IGNvdjJfdnNfb3RoZXJfcG5hX3Jlc3VsdHMgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogIGxlZnRfam9pbiguLCBnZW5lX2NvbnYpICU+JSAKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCAwLjA1IHwgIWdyZXBsKCJFTlNHIiwgZW5zZW1ibF9nZW5lX2lkKSkKCndyaXRlLmNzdihjb3YyX3ZzX290aGVyX3BuYV9yZXN1bHRzX2lkcywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcwMl9zb3J0ZWRfREVBX2NvdmlkX292ZXJfb3RoZXJwbmV1bW9uaWEuY3N2IikKCmNvdjJfdnNfb3RoZXJfcG5hX3Jlc3VsdHNfaWRzCmBgYCAgIApVbnN1cnByaXNpbmdseSwgdGhlcmUgYXJlIHZlcnkgZmV3IHZhbGlkIGRpZmZlcmVuY2VzIGhlcmUKICAgCiMjIyBNb0FNIHBlcmNlbnRhZ2UgICAKYGBge3J9Ck1vQU1fcmVzdWx0c19zb3J0ZWQgPSByZXN1bHRzKHNvcnRlZF9kZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IGMoInBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCIpKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCgpNb0FNX3Jlc3VsdHNfc29ydGVkX2lkcyA9IE1vQU1fcmVzdWx0c19zb3J0ZWQgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiZW5zZW1ibF9nZW5lX2lkIikgJT4lIAogIGxlZnRfam9pbiguLCBnZW5lX2NvbnYpICU+JSAKICBkcGx5cjo6ZmlsdGVyKHBhZGogPCAwLjA1IHwgIWdyZXBsKCJFTlNHIiwgZW5zZW1ibF9nZW5lX2lkKSkKCndyaXRlLmNzdihNb0FNX3Jlc3VsdHNfc29ydGVkX2lkcywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcwMl9zb3J0ZWRfREVBX3BlcmNlbnRfQ0QyMDZfaGlnaC5jc3YiKQoKTW9BTV9yZXN1bHRzX3NvcnRlZF9pZHMKcHJldHR5X01BX3Bsb3QoTW9BTV9yZXN1bHRzX3NvcnRlZCwgbWFydF9uYW1lID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIpCmBgYApUaGlzIGxvb2tzIHF1aXRlIHJlc2FzdXJpbmcuIENEMjA2IGhpIHNhbXBsZXMgaGF2ZSBlbGV2YXRlZCBleHByZXNzaW9uIG9mIEZBQlA0LCBhbnRpY29ycmVsYXRlcyB3aXRoIFNQUDEsIENYQ0w4LiAgICAgICAKICAgCiMjIyBXaGF0IGNhbiBiZSBleHBsYWluZWQgYnkgTW9BTSUgYWxvbmU/ICAgClRNUFJTUzIKYGBge3J9CmQgPSBwbG90Q291bnRzKHNvcnRlZF9kZXMsIAogICAgICAgICAgICAgICBnZW5lID0gIkVOU0cwMDAwMDE4NDAxMiIsCiAgICAgICAgICAgICAgIGludGdyb3VwID0gInBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCIsCiAgICAgICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULAogICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCkKZ2dwbG90KGQsIGFlcyh4ID0gcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoLCB5ID0gY291bnQpKSArCiAgZ2VvbV9wb2ludCgpICsKICB5bGFiKCJNUkMxIChDRDIwNikgQ291bnRzIikKYGBgCgojIyBDb21wYXJpbmcgZGlmZmVyZW50IHBhdGhvZ2VucyAgIAojIyMgSW5kaXZpZHVhbCBwYXRob2dlbnMgICAKYGBge3IgZXZhbD1GQUxTRX0KcGF0aG9nZW5fc2V0ID0gbXBfZGVzWywgIWlzLm5hKG1wJHBhdGhvZ2VuKV0KcGF0aG9nZW5fc2V0JHBhdGhvZ2VuID0gZmFjdG9yKGFzLmNoYXJhY3RlcihwYXRob2dlbl9zZXQkcGF0aG9nZW4pKSAjcmVmYWN0b3IKcGF0aG9nZW5fa21lYW5zID0ga19tZWFuc19maWd1cmUoZGdlID0gcGF0aG9nZW5fc2V0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gIn5wYXRob2dlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSA2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19hbm5vdGF0aW9ucyA9ICJvcmcuSHMuZWcuZGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnNlbWJsX2RiID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9mYWN0b3JzID0gYygicGF0aG9nZW4iLCAiY292aWRfY29uZmlybWVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMywgMywgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IDEyKQpgYGAKUHJvYmFibHkgdG9vIGdyYW51bGFyICAgCiAgIAojIyMgQnJvYWQgZ3JvdXBpbmdzICAKYGBge3IgZXZhbD1GQUxTRX0KaW5mZWN0aW9uX3R5cGVfa21lYW5zID0ga19tZWFuc19maWd1cmUoZGdlID0gcGF0aG9nZW5fc2V0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gIn5pbmZlY3Rpb25fdHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSA0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb19hbm5vdGF0aW9ucyA9ICJvcmcuSHMuZWcuZGIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnNlbWJsX2RiID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF9mYWN0b3JzID0gYygicGF0aG9nZW4iLCAiaW5mZWN0aW9uX3R5cGUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gMTIpCmBgYAoKIyBSYW5kb20gICAKIyMgQUNFMiBjb3VudHMgICAKYGBge3J9CmFjZTJfY291bnRzID0gcGxvdENvdW50cyhtcF9kZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZSA9ICJFTlNHMDAwMDAxMzAyMzQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gImNvdmlkX2NvbmZpcm1lZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWQgPSBULCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBjID0gRikKZ2dwbG90KGFjZTJfY291bnRzLCBhZXMoeCA9IGNvdW50KSkgKwogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiZG9kZ2VyYmx1ZTQiLCApICsKICB5bGFiKCJOdW1iZXIgb2YgU2FtcGxlcyIpICsKICB4bGFiKCJBQ0UyIENvdW50IikKYGBgICAgCiAgIAojIFRyYWplY3Rvcmllcz8gICAKIyMgQWxsIHNhbXBsZXMgICAKV2Ugd2lsbCB1c2UgUENBIGFzIGlzIHJlY29tbWVuZGVkIHRvIG1ha2UgY29tcHV0YXRpb24gZmVhc2libGUuICAgICAgCmBgYHtyfQojc2VsZWN0IGdlbmVzIHdpdGggPiAxMCUgZGV0ZWN0aW9uLCBtZWFuIGNvdW50cyA+IDUKYWxsX2NvdW50cyA9IHQoY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IFQpKSAjbmVlZCBzaXplIG5vcm1hbGl6YXRpb24KcHJvcF9kZXRlY3RlZCA9IGFwcGx5KFggPSBhbGxfY291bnRzLCBNQVJHSU4gPSAyLCBGVU4gPSBkZXRlY3Rpb25fcmF0ZSkKYWxsX2NvdW50cyA9IGFsbF9jb3VudHNbLCBwcm9wX2RldGVjdGVkID4gMC4xXQptZWFuX2RldGVjdGlvbiA9IGNvbE1lYW5zKGFsbF9jb3VudHMpCmFsbF9jb3VudHMgPSBhbGxfY291bnRzWywgbWVhbl9kZXRlY3Rpb24gPj0gNV0KCmFsbF9wY2EgPSBwcmNvbXAoYWxsX2NvdW50cykKZnZpel9laWcoYWxsX3BjYSwgCiAgICAgICAgIGJhcmZpbGwgPSAiZG9kZ2VyYmx1ZTQiLCAKICAgICAgICAgeGxhYiA9ICJQcmluY2lwYWwgQ29tcG9uZW50IiwKICAgICAgICAgeWxhYiA9ICJQZXJjZW50IFZhcmlhbmNlIEV4cGxhaW5lZCIsIAogICAgICAgICBtYWluID0gIiIsCiAgICAgICAgIG5jcCA9IDUwLAogICAgICAgICBnZ3RoZW1lID0gdGhlbWVfYncoKSwKICAgICAgICAgYWRkbGFiZWxzID0gVCkgIzIwIHNob3VsZCBjYXB0dXJlIGFsbW9zdCBldmVyeXRoaW5nCgp0b3RhbF91bWFwID0gdW1hcChYID0gYWxsX2NvdW50cywgCiAgICAgICAgICAgICAgICAgIHBjYSA9IDIwLCAKICAgICAgICAgICAgICAgICAgcGNhX2NlbnRlciA9IFQsIAogICAgICAgICAgICAgICAgICBuX3RocmVhZHMgPSAxLCAKICAgICAgICAgICAgICAgICAgc2NhbGUgPSAiWiIsIAogICAgICAgICAgICAgICAgICBtaW5fZGlzdCA9IDAuMikKcm93bmFtZXModG90YWxfdW1hcCkgPSByb3duYW1lcyhhbGxfY291bnRzKQpjb2xuYW1lcyh0b3RhbF91bWFwKSA9IGMoIlVNQVBfMSIsICJVTUFQXzIiKQp0b3RhbF91bWFwID0gYXMuZGF0YS5mcmFtZSh0b3RhbF91bWFwKQp0b3RhbF91bWFwJHNhbXBsZSA9IHJvd25hbWVzKHRvdGFsX3VtYXApCnRvdGFsX3VtYXAgPSBsZWZ0X2pvaW4odG90YWxfdW1hcCwgbWV0YWRhdGEsIGJ5ID0gInNhbXBsZSIpICU+JSAKICBhcnJhbmdlKHN0dWR5X2lkLCBkYXlfb2ZfaW50dWJhdGlvbikgIyBzbyB3ZSBjYW4gZHJhdyBwYXRocwoKZ2dwbG90KHRvdGFsX3VtYXAsIGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBjb2xvciA9IERpYWdub3NpcykpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfZWxsaXBzZSgpCgpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNoYXBlID0gc3R1ZHlfaWQsIGNvbG9yID0gZGF5X29mX2ludHViYXRpb24pKSArCiAgZ2VvbV9wYXRoKGFycm93ID0gZ3JpZDo6YXJyb3coKSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgZmFjZXRfd3JhcCh+IERpYWdub3NpcykKYGBgICAgClBhdGllbnRzIGFjdHVhbGx5IHNlcGFyYXRlIG91dCByZWFsbHkgd2VsbCBoZXJlLiBUaGlzIG1pZ2h0IGJlIHdvcnRoIGluY2x1ZGluZyBhcyBhIHN1cHBsZW1lbnQuIFdpdGggdGhhdCBzYWlkLCBwcm9iYWJseSBiZXR0ZXIgdG8ganVzdCB1c2UgQ09WSUQgcGF0aWVudHMgZm9yICJ0cmFqZWN0b3JpZXMiLiBJdCBsb29rcyBsaWtlIHRoZXJlIG1heSBiZSBzb21lIHN0cnVjdHVyZSB0byB0aGUgQ09WSUQgZGF0YS4gICAgICAKICAgCgojIyBPbmx5IENPVklEICAgCmBgYHtyfQojcmVtb3ZlIG5vbi1kZXRlY3RlZCBnZW5lcwojbm90ZSB0aGF0IFBDQSBzaG91bGQgb25seSB1c2UgZ2VuZXMgZGV0ZWN0ZWQgaW4gYWxsIHNhbXBsZXMgKDMwODEpCkNPVklEX2NvdW50cyA9IHQoY291bnRzKG1wX2Rlc1ssIG1wX2RlcyREaWFnbm9zaXMgPT0gIkNPVklEXzE5Il0sIG5vcm1hbGl6ZWQgPSBUKSkgI25lZWQgc2l6ZSBub3JtYWxpemF0aW9uCnByb3BfZGV0ZWN0ZWQgPSBhcHBseShYID0gQ09WSURfY291bnRzLCBNQVJHSU4gPSAyLCBGVU4gPSBkZXRlY3Rpb25fcmF0ZSkKQ09WSURfY291bnRzID0gQ09WSURfY291bnRzWywgcHJvcF9kZXRlY3RlZCA+IDAuMV0KbWVhbl9kZXRlY3Rpb24gPSBjb2xNZWFucyhDT1ZJRF9jb3VudHMpCkNPVklEX2NvdW50cyA9IENPVklEX2NvdW50c1ssIG1lYW5fZGV0ZWN0aW9uID49IDVdCgpDT1ZJRF9wY2EgPSBwcmNvbXAoQ09WSURfY291bnRzKQpmdml6X2VpZyhDT1ZJRF9wY2EsIAogICAgICAgICBiYXJmaWxsID0gImRvZGdlcmJsdWU0IiwgCiAgICAgICAgIHhsYWIgPSAiUHJpbmNpcGFsIENvbXBvbmVudCIsCiAgICAgICAgIHlsYWIgPSAiUGVyY2VudCBWYXJpYW5jZSBFeHBsYWluZWQiLCAKICAgICAgICAgbWFpbiA9ICIiLAogICAgICAgICBuY3AgPSA1MCwKICAgICAgICAgZ2d0aGVtZSA9IHRoZW1lX2J3KCksCiAgICAgICAgIGFkZGxhYmVscyA9IFQpICMyMCBzaG91bGQgY2FwdHVyZSBhbG1vc3QgZXZlcnl0aGluZwoKQ09WSURfdW1hcCA9IHVtYXAoWCA9IENPVklEX2NvdW50cywgCiAgICAgICAgICAgICAgICAgIHBjYSA9IDIwLCAKICAgICAgICAgICAgICAgICAgcGNhX2NlbnRlciA9IFQsIAogICAgICAgICAgICAgICAgICBuX3RocmVhZHMgPSAxLCAKICAgICAgICAgICAgICAgICAgc2NhbGUgPSAiWiIsIAogICAgICAgICAgICAgICAgICBtaW5fZGlzdCA9IDAuNCkKcm93bmFtZXMoQ09WSURfdW1hcCkgPSByb3duYW1lcyhDT1ZJRF9jb3VudHMpCmNvbG5hbWVzKENPVklEX3VtYXApID0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCkNPVklEX3VtYXAgPSBhcy5kYXRhLmZyYW1lKENPVklEX3VtYXApCkNPVklEX3VtYXAkc2FtcGxlID0gcm93bmFtZXMoQ09WSURfdW1hcCkKQ09WSURfdW1hcCA9IGxlZnRfam9pbihDT1ZJRF91bWFwLCBtZXRhZGF0YSwgYnkgPSAic2FtcGxlIikgJT4lIAogIGFycmFuZ2Uoc3R1ZHlfaWQsIGRheV9vZl9pbnR1YmF0aW9uKSAjIHNvIHdlIGNhbiBkcmF3IHBhdGhzCgpnZ3Bsb3QoQ09WSURfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gZGF5X29mX2ludHViYXRpb24pKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsKICBnZW9tX3BvaW50KCkKZ2dwbG90KENPVklEX3VtYXAsIGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBzaGFwZSA9IHN0dWR5X2lkLCBjb2xvciA9IGRheV9vZl9pbnR1YmF0aW9uKSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgZ2VvbV9wYXRoKGFycm93ID0gZ3JpZDo6YXJyb3coKSkKYGBgICAgCk5vdCBzbyBtdWNoIHN0cnVjdHVyZSBpdCBzZWVtcy4gICAKCiMgV0dDTkEgICAKV2hhdCBnZW5lIG1vZHVsZXMgYXJlIGFzc29jaWF0ZWQgd2l0aCBjb3ZpZD8gV2hpY2ggY2hhbmdlIHN1YnN0YW50aWFsbHkgb3ZlciB0aW1lIG9uIHZlbnRpbGF0b3I/ICAgCiMjIFRoZXNob2xkaW5nCmBgYHtyfQojc2V0dXAKZW5hYmxlV0dDTkFUaHJlYWRzKG5UaHJlYWRzID0gMTIpCldHQ05BblRocmVhZHMoKQoKIyBDaG9vc2UgYSBzZXQgb2Ygc29mdC10aHJlc2hvbGRpbmcgcG93ZXJzCnBvd2VycyA9IGMoMToyMCkKCiMgQ2FsbCB0aGUgbmV0d29yayB0b3BvbG9neSBhbmFseXNpcyBmdW5jdGlvbnMKc2Z0ID0gcGlja1NvZnRUaHJlc2hvbGQoYWxsX2NvdW50cywgcG93ZXJWZWN0b3IgPSBwb3dlcnMsIHZlcmJvc2UgPSA1LCBuZXR3b3JrVHlwZSA9ICJzaWduZWQiKQoKIyBQbG90IHRoZSByZXN1bHRzOgpzaXplR3JXaW5kb3coOSwgNSkKcGFyKG1mcm93ID0gYygxLDIpKQpjZXgxID0gMC45CgojIFNjYWxlLWZyZWUgdG9wb2xvZ3kgZml0IGluZGV4IGFzIGEgZnVuY3Rpb24gb2YgdGhlIHNvZnQtdGhyZXNob2xkaW5nIHBvd2VyCnBsb3Qoc2Z0JGZpdEluZGljZXNbLDFdLCAKICAgICAtc2lnbihzZnQkZml0SW5kaWNlc1ssM10pKnNmdCRmaXRJbmRpY2VzWywyXSwKICAgICB4bGFiPSJTb2Z0IFRocmVzaG9sZCAocG93ZXIpIiwKICAgICB5bGFiPSJTY2FsZSBGcmVlIFRvcG9sb2d5IE1vZGVsIEZpdCxzaWduZWQgUl4yIiwKICAgICB0eXBlPSJuIiwKICAgICBtYWluID0gcGFzdGUoIlNjYWxlIGluZGVwZW5kZW5jZSIpKQp0ZXh0KHNmdCRmaXRJbmRpY2VzWywxXSwgCiAgICAgLXNpZ24oc2Z0JGZpdEluZGljZXNbLDNdKSpzZnQkZml0SW5kaWNlc1ssMl0sCiAgICAgbGFiZWxzPXBvd2VycywKICAgICBjZXg9Y2V4MSwKICAgICBjb2w9InJlZCIpCgojIHRoaXMgbGluZSBjb3JyZXNwb25kcyB0byB1c2luZyBhbiBSXjIgY3V0LW9mZiBvZiBoCmFibGluZShoPTAuOTAsY29sPSJyZWQiKQoKIyBNZWFuIGNvbm5lY3Rpdml0eSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBzb2Z0LXRocmVzaG9sZGluZyBwb3dlcgpwbG90KHNmdCRmaXRJbmRpY2VzWywxXSwgCiAgICAgc2Z0JGZpdEluZGljZXNbLDVdLAogICAgIHhsYWI9IlNvZnQgVGhyZXNob2xkIChwb3dlcikiLAogICAgIHlsYWI9Ik1lYW4gQ29ubmVjdGl2aXR5IiwgCiAgICAgdHlwZT0ibiIsCiAgICAgbWFpbiA9IHBhc3RlKCJNZWFuIGNvbm5lY3Rpdml0eSIpKQp0ZXh0KHNmdCRmaXRJbmRpY2VzWywxXSwgc2Z0JGZpdEluZGljZXNbLDVdLCBsYWJlbHM9cG93ZXJzLCBjZXg9Y2V4MSxjb2w9InJlZCIpCmBgYCAgIAo3IGxvb2tzIGxpa2UgdGhlIGludGVyc2VjdGlvbiBhZnRlciBhZGRpbmcgaGVhbHRoeSBjb250cm9scyAgIAogICAKIyMgQ28tZXhwcmVzc2lvbiBieSBzaW1pbGFyaXR5IGFuZCBhZGphY2VuY3kgICAKYGBge3J9CnNvZnRQb3dlciA9IDcKYWRqYWNlbmN5ID0gYWRqYWNlbmN5KGFsbF9jb3VudHMsIHBvd2VyID0gc29mdFBvd2VyLCB0eXBlID0gInNpZ25lZCIpCmBgYAoKIyMgVG9wb2xvZ2ljYWwgb3ZlcmxhcCBtYXRyaXggICAKYGBge3J9CiMgVHVybiBhZGphY2VuY3kgaW50byB0b3BvbG9naWNhbCBvdmVybGFwClRPTSA9IFRPTXNpbWlsYXJpdHkoYWRqYWNlbmN5LCBUT01UeXBlID0gInNpZ25lZCIpCmRpc3NUT00gPSAxLVRPTQpgYGAKCiMjIENsdXN0ZXIgYnkgVE9NIGRpc3RhbmNlICAgCmBgYHtyfQpnZW5lVHJlZSA9IGhjbHVzdChhcy5kaXN0KGRpc3NUT00pLCBtZXRob2QgPSAiYXZlcmFnZSIpCgpzaXplR3JXaW5kb3coMTIsOSkKcGxvdChnZW5lVHJlZSwgCiAgICAgeGxhYj0iIiwgCiAgICAgc3ViPSIiLCAKICAgICBtYWluID0gIkdlbmUgY2x1c3RlcmluZyBvbiBUT00tYmFzZWQgZGlzc2ltaWxhcml0eSIsCiAgICAgbGFiZWxzID0gRkFMU0UsIAogICAgIGhhbmcgPSAwLjA0KQpgYGAgICAKICAgCiMjIENyZWF0ZSBtb2R1bGVzICAgCmBgYHtyfQptaW5Nb2R1bGVTaXplID0gMzAgIyBtYXkgbmVlZCB0byBhZGp1c3QKCiMgTWFrZSBtb2R1bGVzIGJhc2VkIG9uIGNsdXN0ZXJzCmR5bmFtaWNNb2RzID0gY3V0cmVlRHluYW1pYyhkZW5kcm8gPSBnZW5lVHJlZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0TSA9IGRpc3NUT00sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWVwU3BsaXQgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFtUmVzcGVjdHNEZW5kcm8gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbkNsdXN0ZXJTaXplID0gbWluTW9kdWxlU2l6ZSkKdGFibGUoZHluYW1pY01vZHMpCmBgYCAgIAogICAKIyMjIExhYmVsIG1vZHVsZXMgKHllYWggdGhpcyBpcyBkdW1iIC0tIHJlbmFtZSBsYXRlcikgICAKYGBge3J9CiMgQ29udmVydCBudW1lcmljIGxhYmVscyBpbnRvIGNvbG9ycwpkeW5hbWljQ29sb3JzID0gbGFiZWxzMmNvbG9ycyhkeW5hbWljTW9kcykKdGFibGUoZHluYW1pY0NvbG9ycykKCiMgUGxvdCB0aGUgZGVuZHJvZ3JhbSBhbmQgY29sb3JzIHVuZGVybmVhdGgKc2l6ZUdyV2luZG93KDgsNikKcGxvdERlbmRyb0FuZENvbG9ycyhnZW5lVHJlZSwgCiAgICAgICAgICAgICAgICAgICAgZHluYW1pY0NvbG9ycywgCiAgICAgICAgICAgICAgICAgICAgIkR5bmFtaWMgVHJlZSBDdXQiLAogICAgICAgICAgICAgICAgICAgIGRlbmRyb0xhYmVscyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgIGhhbmcgPSAwLjAzLAogICAgICAgICAgICAgICAgICAgIGFkZEd1aWRlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICBndWlkZUhhbmcgPSAwLjA1LAogICAgICAgICAgICAgICAgICAgIG1haW4gPSAiR2VuZSBkZW5kcm9ncmFtIGFuZCBtb2R1bGUgY29sb3JzIikKYGBgICAgCkxvb2tzIGxpa2Ugd2UgY2FwdHVyZWQgdGhlIHN0cnVjdHVyZSBwcmV0dHkgd2VsbC4gICAgICAKICAgCiMjIyBNZXJnZSBzaW1pbGFyIG1vZHVsZXMgICAKYGBge3J9CiMgQ2FsY3VsYXRlIGVpZ2VuZ2VuZXMKTUVMaXN0ID0gbW9kdWxlRWlnZW5nZW5lcyhhbGxfY291bnRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcnMgPSBkeW5hbWljQ29sb3JzKQpNRXMgPSBNRUxpc3QkZWlnZW5nZW5lcwoKIyBDYWxjdWxhdGUgZGlzc2ltaWxhcml0eSBvZiBtb2R1bGUgZWlnZW5nZW5lcwpNRURpc3MgPSAxLWNvcihNRXMpCgojIENsdXN0ZXIgbW9kdWxlIGVpZ2VuZ2VuZXMKTUVUcmVlID0gaGNsdXN0KGFzLmRpc3QoTUVEaXNzKSwgCiAgICAgICAgICAgICAgICBtZXRob2QgPSAiYXZlcmFnZSIpCgojIFBsb3QgdGhlIHJlc3VsdApzaXplR3JXaW5kb3coNywgNikKcGxvdChNRVRyZWUsIAogICAgIG1haW4gPSAiQ2x1c3RlcmluZyBvZiBtb2R1bGUgZWlnZW5nZW5lcyIsCiAgICAgeGxhYiA9ICIiLAogICAgIHN1YiA9ICIiKQoKI05vdyBjdXQgYXQgaGVpZ2h0IG9mIDAuNSB0byBnZXQgY29ycmVsYXRpb24gb2YgMC41ICAKI3N0YW5kYXJkIGlzIDAuMjUsIGJ1dCB3ZSBoYXZlIHNvbWUgcmVhbGx5IHNpbWlsYXIgbW9kdWxlcyB0aGF0IGFyZSBub3QgcmVsZXZhbnQKTUVEaXNzVGhyZXMgPSAwLjI1CgojIFBsb3QgdGhlIGN1dCBsaW5lIGludG8gdGhlIGRlbmRyb2dyYW0KYWJsaW5lKGg9TUVEaXNzVGhyZXMsIAogICAgICAgY29sID0gInJlZCIpCgojIENhbGwgYW4gYXV0b21hdGljIG1lcmdpbmcgZnVuY3Rpb24KbWVyZ2UgPSBtZXJnZUNsb3NlTW9kdWxlcyhhbGxfY291bnRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkeW5hbWljQ29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjdXRIZWlnaHQgPSBNRURpc3NUaHJlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IDMpCgojIFRoZSBtZXJnZWQgbW9kdWxlIGNvbG9ycwptZXJnZWRDb2xvcnMgPSBtZXJnZSRjb2xvcnMKCiMgRWlnZW5nZW5lcyBvZiB0aGUgbmV3IG1lcmdlZCBtb2R1bGVzOgptZXJnZWRNRXMgPSBtZXJnZSRuZXdNRXMKCiMgUmVuYW1lIHRvIG1vZHVsZUNvbG9ycwptb2R1bGVDb2xvcnMgPSBtZXJnZWRDb2xvcnMKCiMgQ29uc3RydWN0IG51bWVyaWNhbCBsYWJlbHMgY29ycmVzcG9uZGluZyB0byB0aGUgY29sb3JzCmNvbG9yT3JkZXIgPSBjKCJncmV5Iiwgc3RhbmRhcmRDb2xvcnMoNTApKQptb2R1bGVMYWJlbHMgPSBtYXRjaChtb2R1bGVDb2xvcnMsIGNvbG9yT3JkZXIpLTEKTUVzID0gbWVyZ2VkTUVzCgojcmVwbG90CnNpemVHcldpbmRvdygxMiwgOSkKcGxvdERlbmRyb0FuZENvbG9ycyhnZW5lVHJlZSwgCiAgICAgICAgICAgICAgICAgICAgY2JpbmQoZHluYW1pY0NvbG9ycywgbWVyZ2VkQ29sb3JzKSwKICAgICAgICAgICAgICAgICAgICBjKCJEeW5hbWljIFRyZWUgQ3V0IiwgIk1lcmdlZCBkeW5hbWljIiksCiAgICAgICAgICAgICAgICAgICAgZGVuZHJvTGFiZWxzID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgIGhhbmcgPSAwLjAzLAogICAgICAgICAgICAgICAgICAgIGFkZEd1aWRlID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgZ3VpZGVIYW5nID0gMC4wNSkKYGBgICAgCk5vIGNoYW5nZSAgIAogICAKIyMgUmVsYXRlIGJhY2sgdG8gdHJhaXRzICAgCiMjIyBXaXRob3V0IHZlbnQgc2V0dGluZ3MgICAKYGBge3J9CiMgRGVmaW5lIG51bWJlcnMgb2YgZ2VuZXMgYW5kIHNhbXBsZXMKbkdlbmVzID0gbmNvbChhbGxfY291bnRzKQpuU2FtcGxlcyA9IG5yb3coYWxsX2NvdW50cykKbWV0YWRhdGEgPSBhcy5kYXRhLmZyYW1lKGNvbERhdGEobXBfZGVzKSkKbWRfb2ZfaW50ZXJlc3QgPSBtZXRhZGF0YSAlPiUgCiAgbXV0YXRlKGRlY2Vhc2VkID0gaWZlbHNlKGJpbm5lZF9vdXRjb21lID09ICJEZWNlYXNlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoaGFzX2NvdmlkID0gaWZlbHNlKGNvdmlkX2NvbmZpcm1lZCA9PSAiVFJVRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoY292Ml9kZXRlY3RlZCA9IGlmZWxzZShzYXJzX2NvdjJfZGV0ZWN0ZWQgPT0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoaGFzX3BuZXVtb25pYSA9IGlmZWxzZShwbmFfdHlwZSA9PSAiTm9uLVBuZXVtb25pYSBDb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAxKSkgJT4lIAogIG11dGF0ZShjb2luZmVjdGlvbl9kZXRlY3RlZCA9IGlmZWxzZShhbnlfbm9udmlyYWwgPT0gIlRSVUUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgbXV0YXRlKG90aGVyX3ZpcmFsX3BuYSA9IGlmZWxzZShwbmFfdHlwZSA9PSAiT3RoZXIgVmlyYWwgUG5ldW1vbmlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIG11dGF0ZShub252aXJhbF9wbmEgPSBpZmVsc2UocG5hX3R5cGUgPT0gIk90aGVyIFBuZXVtb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUoaXNfaGVhbHRoeV9jb250cm9sID0gaWZlbHNlKHBuYV90eXBlID09ICJIZWFsdGh5IENvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgZHBseXI6OnNlbGVjdChkZWNlYXNlZCwgaGFzX2NvdmlkLCBjb3YyX2RldGVjdGVkLCBoYXNfcG5ldW1vbmlhLAogICAgICAgICAgICAgICAgb3RoZXJfdmlyYWxfcG5hLCBub252aXJhbF9wbmEsIGlzX2hlYWx0aHlfY29udHJvbCwKICAgICAgICAgICAgICAgIHBlcmNlbnRfbmV1dHJvcGhpbHMsIHBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCwKICAgICAgICAgICAgICAgIHBlcmNlbnRfQ0Q0X3RvdGFsLCBwZXJjZW50X0NEOF90b3RhbCwgZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uLAogICAgICAgICAgICAgICAgQ19SZWFjdGl2ZV9Qcm90ZWluLCBEX0RJTUVSLCBQUk9DQUxDSVRPTklOLCBtZWFuX2FwcykKIyBSZWNhbGN1bGF0ZSBNRXMgd2l0aCBjb2xvciBsYWJlbHMKTUVzMCA9IG1vZHVsZUVpZ2VuZ2VuZXMoYWxsX2NvdW50cywgbW9kdWxlQ29sb3JzKSRlaWdlbmdlbmVzCk1FcyA9IG9yZGVyTUVzKE1FczApCm1vZHVsZVRyYWl0Q29yID0gYmljb3IoTUVzLCAKICAgICAgICAgICAgICAgICAgICAgbWRfb2ZfaW50ZXJlc3QsIAogICAgICAgICAgICAgICAgICAgICB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwKICAgICAgICAgICAgICAgICAgICAgbWF4UE91dGxpZXJzID0gMC4wNSkKbW9kdWxlVHJhaXRQdmFsdWUgPSBjb3JQdmFsdWVTdHVkZW50KG1vZHVsZVRyYWl0Q29yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5TYW1wbGVzKSAlPiUgCiAgYXMubnVtZXJpYygpICU+JSAKICBwLmFkanVzdCguLCBtZXRob2QgPSAiZmRyIikgJT4lIAogIG1hdHJpeChuY29sID0gbmNvbChtb2R1bGVUcmFpdENvcikpCmNvbG5hbWVzKG1vZHVsZVRyYWl0UHZhbHVlKSA9IGNvbG5hbWVzKG1vZHVsZVRyYWl0Q29yKQpyb3duYW1lcyhtb2R1bGVUcmFpdFB2YWx1ZSkgPSByb3duYW1lcyhtb2R1bGVUcmFpdENvcikKbW9kdWxlVHJhaXRDb3JfaG0gPSB0KG1vZHVsZVRyYWl0Q29yKQojanVzdCBtYWtlIHNpZ25pZmljYW50IG9yIG5vdApwdmFsc19obSA9IHQobW9kdWxlVHJhaXRQdmFsdWUpICU+JSAKICBhcy5tYXRyaXgoKQpwdmFsc19obVtwdmFsc19obSA8IDAuMDVdID0gIiIKcHZhbHNfaG1bcHZhbHNfaG0gIT0gIiJdID0gIk5TIgoKbGFicyA9IGMoIkRlY2Vhc2VkIiwgIkNPVklELTE5IiwgIlNBUlMtQ29WLTIgRGV0ZWN0ZWQiLCAiQW55IFBuZXVtb25pYSIsICJPdGhlciBWaXJhbCBQbmV1bW9uaWEiLCAiT3RoZXIgUG5ldW1vbmlhIiwKICAgICAgICAgIkhlYWx0aHkgQ29udHJvbCIsICIlIE5ldXRyb3BoaWxzIiwgIiUgTWFjcm9waGFnZXMgQ0QyMDYtaGlnaCIsICIlIENENCBUIiwgIiUgQ0Q4IFQiLAogICAgICAgICAiRGF5IG9mIEludHViYXRpb24iLCAiQ1JQIiwgIkQtRGltZXIiLCAiUHJvY2FsY2l0b25pbiIsICJNZWFuIEFQUyIpCm1vZHVsZV9jb3JfaGVhdG1hcCA9IHBoZWF0bWFwKG1hdCA9IG1vZHVsZVRyYWl0Q29yX2htLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfcm93ID0gbGFicywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX2NvbCA9IHBhc3RlKCJNb2R1bGUiLCBjKDE6bmNvbChNRXMpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlfbnVtYmVycyA9IHB2YWxzX2htLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKG4gPSA3LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUmRCdSIpKSkoMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nbGVfY29sID0gMzE1KQptb2R1bGVfY29yX2hlYXRtYXAgPSBwaGVhdG1hcChtYXQgPSBtb2R1bGVUcmFpdENvcl9obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX3JvdyA9IGxhYnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19jb2wgPSBwYXN0ZSgiTW9kdWxlIiwgYygxOm5jb2woTUVzKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBwdmFsc19obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlJkQnUiKSkpKDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlX2NvbCA9IDMxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDMyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250c2l6ZSA9IDI0KQpgYGAKTW9kdWxlIDEyICh0dXJxdW9pc2UpIGxvb2tzIGxpa2UgdGhlIGtleSBNb0FNIGNsdXN0ZXIsIDQgKGJsdWUpIGlzIGtleSBUUkFNLCBhbmQgbW9kdWxlIDE0IChwdXJwbGUpIGlzIGxpa2VseSBvdXIgSUZOIGNsdXN0ZXIuCgojIyMgV2l0aCB2ZW50IHNldHRpbmdzICAgCmBgYHtyfQojIERlZmluZSBudW1iZXJzIG9mIGdlbmVzIGFuZCBzYW1wbGVzCm5HZW5lcyA9IG5jb2woYWxsX2NvdW50cykKblNhbXBsZXMgPSBucm93KGFsbF9jb3VudHMpCgptZF9vZl9pbnRlcmVzdCA9IG1ldGFkYXRhICU+JSAKICBtdXRhdGUoZGVjZWFzZWQgPSBpZmVsc2UoYmlubmVkX291dGNvbWUgPT0gIkRlY2Vhc2VkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIG11dGF0ZShoYXNfY292aWQgPSBpZmVsc2UoY292aWRfY29uZmlybWVkID09ICJUUlVFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIG11dGF0ZShjb3YyX2RldGVjdGVkID0gaWZlbHNlKHNhcnNfY292Ml9kZXRlY3RlZCA9PSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIG11dGF0ZShoYXNfcG5ldW1vbmlhID0gaWZlbHNlKHBuYV90eXBlID09ICJOb24tUG5ldW1vbmlhIENvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDEpKSAlPiUgCiAgbXV0YXRlKGNvaW5mZWN0aW9uX2RldGVjdGVkID0gaWZlbHNlKGFueV9ub252aXJhbCA9PSAiVFJVRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBtdXRhdGUob3RoZXJfdmlyYWxfcG5hID0gaWZlbHNlKHBuYV90eXBlID09ICJPdGhlciBWaXJhbCBQbmV1bW9uaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IDApKSAlPiUgCiAgbXV0YXRlKG5vbnZpcmFsX3BuYSA9IGlmZWxzZShwbmFfdHlwZSA9PSAiT3RoZXIgUG5ldW1vbmlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAwKSkgJT4lIAogIG11dGF0ZShpc19oZWFsdGh5X2NvbnRyb2wgPSBpZmVsc2UocG5hX3R5cGUgPT0gIkhlYWx0aHkgQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gMCkpICU+JSAKICBkcGx5cjo6c2VsZWN0KGRlY2Vhc2VkLCBoYXNfY292aWQsIGNvdjJfZGV0ZWN0ZWQsIGhhc19wbmV1bW9uaWEsCiAgICAgICAgICAgICAgICBvdGhlcl92aXJhbF9wbmEsIG5vbnZpcmFsX3BuYSwgaXNfaGVhbHRoeV9jb250cm9sLAogICAgICAgICAgICAgICAgcGVyY2VudF9uZXV0cm9waGlscywgcGVyY2VudF90b3RhbF9DRDIwNl9oaWdoLAogICAgICAgICAgICAgICAgcGVyY2VudF9DRDRfdG90YWwsIHBlcmNlbnRfQ0Q4X3RvdGFsLCBmaW5pdGVfZGF5X29mX2ludHViYXRpb24sCiAgICAgICAgICAgICAgICBDX1JlYWN0aXZlX1Byb3RlaW4sIERfRElNRVIsIFBST0NBTENJVE9OSU4sIG1lYW5fYXBzLAogICAgICAgICAgICAgICAgU3RhdGljX0NvbXBsaWFuY2UsIFBGX3JhdGlvKQoKIyBSZWNhbGN1bGF0ZSBNRXMgd2l0aCBjb2xvciBsYWJlbHMKTUVzMCA9IG1vZHVsZUVpZ2VuZ2VuZXMoYWxsX2NvdW50cywgbW9kdWxlQ29sb3JzKSRlaWdlbmdlbmVzCk1FcyA9IG9yZGVyTUVzKE1FczApCm1vZHVsZVRyYWl0Q29yID0gYmljb3IoTUVzLCAKICAgICAgICAgICAgICAgICAgICAgbWRfb2ZfaW50ZXJlc3QsIAogICAgICAgICAgICAgICAgICAgICB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwKICAgICAgICAgICAgICAgICAgICAgbWF4UE91dGxpZXJzID0gMC4wNSkKCm1vZHVsZVRyYWl0UHZhbHVlID0gY29yUHZhbHVlU3R1ZGVudChtb2R1bGVUcmFpdENvciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuU2FtcGxlcykgJT4lIAogIGFzLm51bWVyaWMoKSAlPiUgCiAgcC5hZGp1c3QoLiwgbWV0aG9kID0gImZkciIpICU+JSAKICBtYXRyaXgobmNvbCA9IG5jb2wobW9kdWxlVHJhaXRDb3IpKQpjb2xuYW1lcyhtb2R1bGVUcmFpdFB2YWx1ZSkgPSBjb2xuYW1lcyhtb2R1bGVUcmFpdENvcikKcm93bmFtZXMobW9kdWxlVHJhaXRQdmFsdWUpID0gcm93bmFtZXMobW9kdWxlVHJhaXRDb3IpCgptb2R1bGVUcmFpdENvcl9obSA9IHQobW9kdWxlVHJhaXRDb3IpCiNqdXN0IG1ha2Ugc2lnbmlmaWNhbnQgb3Igbm90CnB2YWxzX2htID0gdChtb2R1bGVUcmFpdFB2YWx1ZSkgJT4lIAogIGFzLm1hdHJpeCgpCnB2YWxzX2htW3B2YWxzX2htIDwgMC4wNV0gPSAiIgpwdmFsc19obVtwdmFsc19obSAhPSAiIl0gPSAiTlMiCgoKbGFicyA9IGMoIkRlY2Vhc2VkIiwgIkNPVklELTE5IiwgIlNBUlMtQ29WLTIgRGV0ZWN0ZWQiLCAiQW55IFBuZXVtb25pYSIsICJPdGhlciBWaXJhbCBQbmV1bW9uaWEiLCAiT3RoZXIgUG5ldW1vbmlhIiwKICAgICAgICAgIkhlYWx0aHkgQ29udHJvbCIsICIlIE5ldXRyb3BoaWxzIiwgIiUgTWFjcm9waGFnZXMgQ0QyMDYtaGlnaCIsICIlIENENCBUIiwgIiUgQ0Q4IFQiLAogICAgICAgICAiRGF5IG9mIEludHViYXRpb24iLCAiQ1JQIiwgIkQtRGltZXIiLCAiUHJvY2FsY2l0b25pbiIsICJNZWFuIEFQUyIsCiAgICAgICAgICJTdGF0aWMgQ29tcGxpYW5jZSIsICJQL0YgUmF0aW8iKQptb2R1bGVfY29yX2hlYXRtYXAgPSBwaGVhdG1hcChtYXQgPSBtb2R1bGVUcmFpdENvcl9obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzX3JvdyA9IGxhYnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19jb2wgPSBwYXN0ZSgiTW9kdWxlIiwgYygxOm5jb2woTUVzKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBwdmFsc19obSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlJkQnUiKSkpKDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZ2xlX2NvbCA9IDMxNSkKbW9kdWxlX2Nvcl9oZWF0bWFwID0gcGhlYXRtYXAobWF0ID0gbW9kdWxlVHJhaXRDb3JfaG0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19yb3cgPSBsYWJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfY29sID0gcGFzdGUoIk1vZHVsZSIsIGMoMTpuY29sKE1FcykpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheV9udW1iZXJzID0gcHZhbHNfaG0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJSZEJ1IikpKSgxMDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmdsZV9jb2wgPSAzMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSAzMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSAyNCkKYGBgICAgCk1vZHVsZSAxMyAoc2FsbW9uKSBtYXkgYWxzbyBiZSBpbnRlcmVzdGluZy4gQ29ycmVsYXRlcyB3aXRoIENPVklELCBDUlAsIGx5bXBob2N5dGVzLCBhbmQgdmVudCBwYXJhbXMhICAgIAogICAKIyMjIFNhbml0eSBjaGVjazogYXJlIHRoZSBDRDIwNiBtb2R1bGVzIFRSQU0vTW9BTSBtYXJrZXJzPyAgIApgYGB7cn0KbW9kdWxlX2Fzc2lnbm1lbnRzID0gZGF0YS5mcmFtZShlbnNlbWJsX2dlbmVfaWQgPSBjb2xuYW1lcyhhbGxfY291bnRzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R1bGUgPSBmYWN0b3IobWVyZ2VkQ29sb3JzKSkgJT4lIAogIGxlZnRfam9pbiguLCBnZW5lX2NvbnYpCndyaXRlLmNzdihtb2R1bGVfYXNzaWdubWVudHMsCiAgICAgICAgICAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzIxX1dHQ05BX21vZHVsZV9hc3NpZ25tZW50cy5jc3YiKQoKY2QyMDZfY29ycmVsYXRlZCA9IHN1YnNldChtb2R1bGVfYXNzaWdubWVudHMsIG1vZHVsZSA9PSAiYmx1ZSIpCmNkMjA2X2FudGljb3JyZWxhdGVkID0gc3Vic2V0KG1vZHVsZV9hc3NpZ25tZW50cywgbW9kdWxlID09ICJ0dXJxdW9pc2UiKQpjZDIwNl9jb3JyZWxhdGVkCmNkMjA2X2FudGljb3JyZWxhdGVkCmBgYApQcmV0dHkgaWRlYWwsIHllYWggICAKICAgCiAgIAojIyMgQ09WSUQtYXNzb2NpYXRlZCAgIApQdXJwbGUgY29udGFpbnMgYWxsIG9mIHRoZSBDb1YtMiBnZW5lcyEgICAKYGBge3J9CmNvdmlkX2NvcnJlbGF0ZWRfY2QyMDZfdW5jb3JyZWxhdGVkID0gc3Vic2V0KG1vZHVsZV9hc3NpZ25tZW50cywgbW9kdWxlID09ICJwdXJwbGUiKQpjb3ZpZF9jb3JyZWxhdGVkX2NkMjA2X3VuY29ycmVsYXRlZAp3cml0ZS5jc3YoY292aWRfY29ycmVsYXRlZF9jZDIwNl91bmNvcnJlbGF0ZWQsCiAgICAgICAgICAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzIxX3B1cnBsZV9tb2R1bGVfMTRfZ2VuZXMuY3N2IikKYGBgClByZXR0eSBjbGFzc2ljIGludGVyZmVyb24gcmVzcG9uc2UuIExvb2sgYXQgdGhlIEdPLiAgIAogICAKYGBge3J9CiNmcm9tIGtfbWVhbnNfZmlndXJlCmNvbXBsZXRlX2NvdW50cyA9IGNvdW50cyhtcF9kZXMsIG5vcm1hbGl6ZWQgPSBUKQp1bml2ZXJzZSA9IHJvd25hbWVzKGNvbXBsZXRlX2NvdW50c1tyb3dTdW1zKGNvbXBsZXRlX2NvdW50cykgPiAwLCBdKQpmaXNoZXJUZXN0ID0gbmV3KCJjbGFzc2ljQ291bnQiLCB0ZXN0U3RhdGlzdGljID0gR09GaXNoZXJUZXN0LCBuYW1lID0gIkZpc2hlciB0ZXN0IikKCmNsdXN0ZXJfZ2VuZXMgPSBjb3ZpZF9jb3JyZWxhdGVkX2NkMjA2X3VuY29ycmVsYXRlZCRlbnNlbWJsX2dlbmVfaWQKc2VsZWN0aW9uID0gYXMubnVtZXJpYyh1bml2ZXJzZSAlaW4lIGNsdXN0ZXJfZ2VuZXMpCm5hbWVzKHNlbGVjdGlvbikgPSB1bml2ZXJzZQpnb19kYXRhID0gbmV3KCJ0b3BHT2RhdGEiLCAKICAgICAgICAgICAgICBvbnRvbG9neSA9ICJCUCIsIAogICAgICAgICAgICAgIGFsbEdlbmVzID0gc2VsZWN0aW9uLAogICAgICAgICAgICAgIGdlbmVTZWwgPSBmdW5jdGlvbih4KXsKICAgICAgICAgICAgICAgIHJldHVybih4ID09IDEpfSwKICAgICAgICAgICAgICBhbm5vdCA9IGFubkZVTi5vcmcsIAogICAgICAgICAgICAgIG1hcHBpbmcgPSAib3JnLkhzLmVnLmRiIiwgCiAgICAgICAgICAgICAgSUQgPSAiZW5zZW1ibCIpCiAgCiNydW4gRmlzaGVyIHRlc3QKdGVzdF9yZXN1bHRzID0gZ2V0U2lnR3JvdXBzKGdvX2RhdGEsIGZpc2hlclRlc3QpCm1vZHVsZTE0X3Njb3JlID0gYXMuZGF0YS5mcmFtZShzY29yZSh0ZXN0X3Jlc3VsdHMpKQpjb2xuYW1lcyhtb2R1bGUxNF9zY29yZSkgPSAicHZhbCIKbW9kdWxlMTRfc2NvcmUgPSByb3duYW1lc190b19jb2x1bW4obW9kdWxlMTRfc2NvcmUsIHZhciA9ICJnb19pZCIpCiAgCiNhZGp1c3QgcC12YWx1ZXMgYW5kIHRha2Ugc2lnbmlmaWNhbnQKbW9kdWxlMTRfc2NvcmUkcGFkaiA9IHAuYWRqdXN0KG1vZHVsZTE0X3Njb3JlJHB2YWwsIG1ldGhvZCA9ICJmZHIiKQptb2R1bGUxNF9zY29yZSA9IHN1YnNldChtb2R1bGUxNF9zY29yZSwgcGFkaiA8IDAuMDUpCm1vZHVsZTE0X3Njb3JlJGRlc2NyaXB0aW9uID0gTkEKZm9yKGkgaW4gMTpucm93KG1vZHVsZTE0X3Njb3JlKSkKewogIG1vZHVsZTE0X3Njb3JlJGRlc2NyaXB0aW9uW2ldID0gR09URVJNW1ttb2R1bGUxNF9zY29yZSRnb19pZFtpXV1dQFRlcm0KfQoKI2FkZCBkZXNjcmlwdGlvbnMKbW9kdWxlMTRfc2NvcmUkZnVsbF9nbyA9IHBhc3RlKG1vZHVsZTE0X3Njb3JlJGdvX2lkLCBtb2R1bGUxNF9zY29yZSRkZXNjcmlwdGlvbikKd3JpdGUuY3N2KG1vZHVsZTE0X3Njb3JlLAogICAgICAgICAgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9wdXJwbGVfbW9kdWxlXzE0X0dPLmNzdiIpCm1vZHVsZTE0X3Njb3JlCmBgYApQcmV0dHkgbXVjaCBhbGwgVHlwZSBJIGludGVyZmVyb24gcmVsYXRlZC4gTW9zdCBvZiB0aGUgcGFwZXIgaXMgaGVyZS4gICAKICAgCiMjIyBNb2R1bGUgMTMgICAKVGhpcyBtb2R1bGUgaGFzIElSRjEgYW5kIHRoZSBNSEMtSSBnZW5lcyAgIApgYGB7cn0KbW9kdWxlMTMgPSBzdWJzZXQobW9kdWxlX2Fzc2lnbm1lbnRzLCBtb2R1bGUgPT0gInNhbG1vbiIpCm1vZHVsZTEzCndyaXRlLmNzdihtb2R1bGUxMywKICAgICAgICAgICIvcHJvamVjdHMvYjEwMzgvUHVsbW9uYXJ5L3JncmFudC9zY3JpcHRfYnVsay9BbmFseXNpcy8yMDA3MjFfc2FsbW9uX21vZHVsZV8xM19nZW5lcy5jc3YiKQpgYGAKICAgCmBgYHtyfQojZnJvbSBrX21lYW5zX2ZpZ3VyZQpjbHVzdGVyX2dlbmVzID0gbW9kdWxlMTMkZW5zZW1ibF9nZW5lX2lkCnNlbGVjdGlvbiA9IGFzLm51bWVyaWModW5pdmVyc2UgJWluJSBjbHVzdGVyX2dlbmVzKQpuYW1lcyhzZWxlY3Rpb24pID0gdW5pdmVyc2UKZ29fZGF0YSA9IG5ldygidG9wR09kYXRhIiwgCiAgICAgICAgICAgICAgb250b2xvZ3kgPSAiQlAiLCAKICAgICAgICAgICAgICBhbGxHZW5lcyA9IHNlbGVjdGlvbiwKICAgICAgICAgICAgICBnZW5lU2VsID0gZnVuY3Rpb24oeCl7CiAgICAgICAgICAgICAgICByZXR1cm4oeCA9PSAxKX0sCiAgICAgICAgICAgICAgYW5ub3QgPSBhbm5GVU4ub3JnLCAKICAgICAgICAgICAgICBtYXBwaW5nID0gIm9yZy5Icy5lZy5kYiIsIAogICAgICAgICAgICAgIElEID0gImVuc2VtYmwiKQogIAojcnVuIEZpc2hlciB0ZXN0CnRlc3RfcmVzdWx0cyA9IGdldFNpZ0dyb3Vwcyhnb19kYXRhLCBmaXNoZXJUZXN0KQptb2R1bGUxM19zY29yZSA9IGFzLmRhdGEuZnJhbWUoc2NvcmUodGVzdF9yZXN1bHRzKSkKY29sbmFtZXMobW9kdWxlMTNfc2NvcmUpID0gInB2YWwiCm1vZHVsZTEzX3Njb3JlID0gcm93bmFtZXNfdG9fY29sdW1uKG1vZHVsZTEzX3Njb3JlLCB2YXIgPSAiZ29faWQiKQogIAojYWRqdXN0IHAtdmFsdWVzIGFuZCB0YWtlIHNpZ25pZmljYW50Cm1vZHVsZTEzX3Njb3JlJHBhZGogPSBwLmFkanVzdChtb2R1bGUxM19zY29yZSRwdmFsLCBtZXRob2QgPSAiZmRyIikKbW9kdWxlMTNfc2NvcmUgPSBzdWJzZXQobW9kdWxlMTNfc2NvcmUsIHBhZGogPCAwLjA1KQojIG1vZHVsZTEzX3Njb3JlJGRlc2NyaXB0aW9uID0gTkEKIyBmb3IoaSBpbiAxOm5yb3cobW9kdWxlMTNfc2NvcmUpKQojIHsKIyAgIG1vZHVsZTEzX3Njb3JlJGRlc2NyaXB0aW9uW2ldID0gR09URVJNW1ttb2R1bGUxM19zY29yZSRnb19pZFtpXV1dQFRlcm0KIyB9CiMgCiMgI2FkZCBkZXNjcmlwdGlvbnMKIyBtb2R1bGUxM19zY29yZSRmdWxsX2dvID0gcGFzdGUobW9kdWxlMTNfc2NvcmUkZ29faWQsIG1vZHVsZTEzX3Njb3JlJGRlc2NyaXB0aW9uKQojIHdyaXRlLmNzdihtb2R1bGUxM19zY29yZSwKIyAgICAgICAgICAgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzLzIwMDcyMV9zYWxtb25fbW9kdWxlXzEzX0dPLmNzdiIpCiMgbW9kdWxlMTNfc2NvcmUKYGBgCk5vIHNpZ25pZmljYW50IGhpdHMuICAgCiAgIAojIyBQbG90IGludGVyZXN0aW5nIG1vZHVsZXMgICAKIyMjIFB1cnBsZSBtb2R1bGUgKDE0KSBhbmQgZGlhZ25vc2lzLCBvdXRjb21lICAgCmBgYHtyfQp0b3RhbF91bWFwID0gTUVMaXN0JGF2ZXJhZ2VFeHByICU+JSAKICByb3duYW1lc190b19jb2x1bW4oInNhbXBsZSIpICU+JSAKICBsZWZ0X2pvaW4odG90YWxfdW1hcCwgLikKY292aWRfdW1hcCA9IHRvdGFsX3VtYXAgJT4lIAogIGRwbHlyOjpmaWx0ZXIoY292aWRfY29uZmlybWVkID09IFRSVUUpCgpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNpemUgPSBBRXB1cnBsZSwgY29sb3IgPSBEaWFnbm9zaXMpKSArCiAgZ2VvbV9wb2ludCgpCm1vZHVsZTE0X3VtYXAgPSBnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNpemUgPSBBRXB1cnBsZSwgY29sb3IgPSBwbmFfdHlwZSwgc2hhcGUgPSBiaW5uZWRfb3V0Y29tZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gZmlnMl9wYWxbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uLVBuZXVtb25pYSBDb250cm9sIiA9IGZpZzJfcGFsWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklELTE5IiA9IGZpZzJfcGFsWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIFZpcmFsIFBuZXVtb25pYSIgPSBmaWcyX3BhbFszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBQbmV1bW9uaWEiID0gZmlnMl9wYWxbNF0pLAogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImJsYWNrIikgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIiIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiRGVjZWFzZWQiID0gMTMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlzY2hhcmdlZCIgPSAxOSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnBhdGllbnQgRmFjaWxpdHkiID0gMTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIiID0gMTgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAxKSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiTW9kdWxlIDE0IEV4cHJlc3Npb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgPSBjKDEsIDEwKSkgKwogIHhsYWIoIlVNQVAgMSIpICsKICB5bGFiKCJVTUFQIDIiKQptb2R1bGUxNF91bWFwIApgYGAgICAKICAgCiMjIyBDQ0wyNCAgICAgIApgYGB7cn0KY2NsMjRfY291bnRzID0gcm93bmFtZXNfdG9fY29sdW1uKGNjbDI0X2NvdW50cywgdmFyID0gInNhbXBsZSIpCmNjbDI0X2NvdW50cyA9IGNjbDI0X2NvdW50c1ssIDE6Ml0KY29sbmFtZXMoY2NsMjRfY291bnRzKVsyXSA9ICJDQ0wyNCIKdG90YWxfdW1hcCA9IGxlZnRfam9pbih0b3RhbF91bWFwLCBjY2wyNF9jb3VudHMpCmNjbDI0X3VtYXAgPSBnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNpemUgPSBDQ0wyNCwgY29sb3IgPSBwbmFfdHlwZSwgc2hhcGUgPSBiaW5uZWRfb3V0Y29tZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gZmlnMl9wYWxbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uLVBuZXVtb25pYSBDb250cm9sIiA9IGZpZzJfcGFsWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklELTE5IiA9IGZpZzJfcGFsWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIFZpcmFsIFBuZXVtb25pYSIgPSBmaWcyX3BhbFszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBQbmV1bW9uaWEiID0gZmlnMl9wYWxbNF0pLAogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImJsYWNrIikgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIiIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiRGVjZWFzZWQiID0gMTMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlzY2hhcmdlZCIgPSAxOSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnBhdGllbnQgRmFjaWxpdHkiID0gMTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIiID0gMTgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAxKSArCnNjYWxlX3NpemVfY29udGludW91cyhuYW1lID0gIkNDTDI0IENvdW50cyIsIHRyYW5zID0gImxvZzEwIiwgcmFuZ2UgPSBjKDEsIDEwKSkgKwogIHhsYWIoIlVNQVAgMSIpICsKICB5bGFiKCJVTUFQIDIiKQpjY2wyNF91bWFwIApgYGAKVGhpcyBpcyByZWFsbHkgY29vbCEgVGhpcyBpc29sYXRlcyBtb3N0IHRoZSB0aGUgSUZOLW5vbi1yZXNwb25zaXZlIENPVklEIHBhdGllbnRzLiBNYXliZSB0aGlzIGRyaXZlcyBoZXRlcm9nZW5laXR5IGluIGNlbGx0eXBlIGNvbXBvc2l0aW9uIGluIHRoZSBsdW5nPyAgIAogICAKYGBge3J9CnRjZWxsX3VtYXAgPSBnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNpemUgPSBwZXJjZW50X0NEM190b3RhbCwgY29sb3IgPSBwbmFfdHlwZSwgc2hhcGUgPSBiaW5uZWRfb3V0Y29tZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhbWlseSA9ICJBcmlhbCIpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJIZWFsdGh5X0NvbnRyb2wiID0gZmlnMl9wYWxbNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uLVBuZXVtb25pYSBDb250cm9sIiA9IGZpZzJfcGFsWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPVklELTE5IiA9IGZpZzJfcGFsWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIFZpcmFsIFBuZXVtb25pYSIgPSBmaWcyX3BhbFszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBQbmV1bW9uaWEiID0gZmlnMl9wYWxbNF0pLAogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gImJsYWNrIikgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIiIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiRGVjZWFzZWQiID0gMTMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlzY2hhcmdlZCIgPSAxOSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnBhdGllbnQgRmFjaWxpdHkiID0gMTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RoZXIiID0gMTgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAxKSArCnNjYWxlX3NpemVfY29udGludW91cyhuYW1lID0gIlBlcmNlbnQgTHltcGhvY3l0ZXMiLCByYW5nZSA9IGMoMSwgMTApKSArCiAgeGxhYigiVU1BUCAxIikgKwogIHlsYWIoIlVNQVAgMiIpCgp0Y2VsbF91bWFwIApgYGAKCgogICAKIyMjIEJyb3duL3R1cnF1b2lzZSBtb2R1bGVzIGFuZCBkYXkgb2YgaW50dWJhdGlvbiBpbiBDT1ZJRCBwYXRpZW50cyAgIApUUkFNIGNvbnRlbnQgICAKYGBge3J9CmdncGxvdCh0b3RhbF91bWFwLCBhZXMoeCA9IGRheV9vZl9pbnR1YmF0aW9uLCB5ID0gQUVibHVlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKQoKZ2dwbG90KHRvdGFsX3VtYXAsIGFlcyh4ID0gZGF5X29mX2ludHViYXRpb24sIHkgPSBBRXR1cnF1b2lzZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKYGBgCk5vdCBtdWNoIG9mIGEgY29ycmVsYXRpb24uLi5tYXliZSBhIGZsYXQgbGluZSwgYXMgSSBndWVzcyB3b3VsZCBiZSBleHBlY3RlZCB3aXRoIG5lYXItY29uc3RhbnQgcmVjcnVpdG1lbnQuIAogICAKIyMgRWZmZWN0IG9mIE9SRjggZXhwcmVzc2lvbiAgIAojIyMgSXNvbGF0ZSBjb3VudHMgICAKYGBge3J9Cm9yZjggPSBjb3YyX2dlbmVzJGVuc2VtYmxfZ2VuZV9pZFt3aGljaChjb3YyX2dlbmVzJGdlbmVfbmFtZSA9PSAiT1JGOCIpXQpvcmY4X2NvdW50cyA9IHBsb3RDb3VudHMobXBfZGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUgPSBvcmY4LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gInBuYV90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZCA9IFQsIAogICAgICAgICAgICAgICAgICAgICAgICAgcGMgPSBUKQpvcmY4X3NhbXBsZXMgPSByb3duYW1lcyhzdWJzZXQob3JmOF9jb3VudHMsIGNvdW50ID4wKSkKCmdncGxvdChvcmY4X2NvdW50cywgYWVzKHggPSBwbmFfdHlwZSwgeSA9IGNvdW50KSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihhZXMoY29sb3IgPSBjb3VudCA+IDApKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICB5bGFiKCJPUkY4IENvdW50cyIpICsKICB4bGFiKCIiKSAKYGBgICAgCiAgIApOb3QgYSB0b24gb2YgZGV0ZWN0aW9uIGJ1dCB2ZXJ5IGNsZWFuLiAgIAogICAKIyMjIEFzc29jaWF0aW9uIHdpdGggaW50ZXJmZXJvbiByZXNwb25zZXMgICAKYGBge3J9Cm1wX2RlcyRvcmY4X2RldGVjdGVkID0gbXBfZGVzJHNhbXBsZSAlaW4lIG9yZjhfc2FtcGxlcwp0b3RhbF91bWFwJG9yZjhfZGV0ZWN0ZWQgPSB0b3RhbF91bWFwJHNhbXBsZSAlaW4lIG9yZjhfc2FtcGxlcwpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIHNpemUgPSBNRXB1cnBsZSwgY29sb3IgPSBEaWFnbm9zaXMsIHNoYXBlID0gb3JmOF9kZXRlY3RlZCkpICsKICBnZW9tX3BvaW50KCkKYGBgICAKUHJldHR5IGNsZWFyIHNwYXRpYWwgY29ycmVsYXRpb24uLi5idXQgaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbj8gICAKICAgCmBgYHtyfQpnZ3Bsb3QodG90YWxfdW1hcCwgYWVzKHggPSBvcmY4X2RldGVjdGVkLCB5ID0gTUVwdXJwbGUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKGFlcyhjb2xvciA9IERpYWdub3NpcykpCgpoaWdoX2NvdjIgPSBjb2xuYW1lcyhjb3YyX2NvdW50cylbY29sU3Vtcyhjb3YyX2NvdW50cykgPiA1MF0KdG90YWxfdW1hcCRjb3YyX2RldGVjdGVkID0gdG90YWxfdW1hcCRzYW1wbGUgJWluJSBoaWdoX2NvdjIKZ2dwbG90KHRvdGFsX3VtYXAsIGFlcyh4ID0gY292Ml9kZXRlY3RlZCwgeSA9IE1FcHVycGxlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihhZXMoY29sb3IgPSBEaWFnbm9zaXMpKQpgYGAKVGhpcyByZWFsbHkganVzdCBjb3JyZWxhdGVzIHdpdGggb3ZlcmFsbCB2aXJhbCBsb2FkICh3aGljaCBjb3JyZWxhdGVzLCBpbiB0dXJuLCB3aXRoIE9SRjggbGV2ZWxzKS4gTm8gc3VwcG9ydCByZWFsbHkgZm9yIHRoZSBPUkY4IGluaGliaXRpb24gb2YgdGhlIElGTiByZXNwb25zZSwgYXQgbGVhc3QgYXQgdGhpcyBzdGFnZS4gICAKICAgCiMgSW50ZXJmZXJvbiByZXNwb25zZSBvdmVyIHRpbWUgICAKIyMgV0dDTkEgTW9kdWxlIHB1cnBsZSAgIAojIyMgQXZlcmFnZSBleHByZXNzaW9uICAgCmBgYHtyfQpnZ3Bsb3QoY292aWRfdW1hcCwgYWVzKHggPSBmaW5pdGVfZGF5X29mX2ludHViYXRpb24sIHkgPSBBRXB1cnBsZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpCmBgYAogICAKIyMgR08gQ2F0ZWdvcmllcyAgIAojIyMgUHVsbCBmcm9tIGJpb21hcnQgICAKYGBge3J9Cmh1bWFuX21hcnQgPSB1c2VFbnNlbWJsKCJlbnNlbWJsIiwgZGF0YXNldCA9ICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiLCBHUkNoID0gMzcpCgojbm93IHB1bGwgZG93biBnZW5lcyBiYXNlZCBvbiBnZW5lIG9udG9sb2d5IChHTykgZGVmaW5pdGlvbnMKdHlwZUlfSUZOX3Jlc3BvbnNlID0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoImVuc2VtYmxfZ2VuZV9pZCIsICJleHRlcm5hbF9nZW5lX25hbWUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVycyA9ICJnbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9ICJHTzowMDYwMzM3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFydCA9IGh1bWFuX21hcnQpCgpJRk5nX3Jlc3BvbnNlID0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoImVuc2VtYmxfZ2VuZV9pZCIsICJleHRlcm5hbF9nZW5lX25hbWUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVycyA9ICJnbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9ICJHTzowMDYwMzMzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFydCA9IGh1bWFuX21hcnQpCmBgYCAgIAogICAKIyMjIEFzc2lnbiBtZWFuIGV4cHJlc3Npb24gICAKYGBge3J9CnVuZmlsdGVyZWRfY291bnRzID0gY291bnRzKG1wX2Rlcywgbm9ybWFsaXplZCA9IFQpCnR5cGVJX0lGTl9yZXNwb25zZSA9IHN1YnNldCh0eXBlSV9JRk5fcmVzcG9uc2UsIGVuc2VtYmxfZ2VuZV9pZCAlaW4lIHJvd25hbWVzKHVuZmlsdGVyZWRfY291bnRzKSkKSUZOZ19yZXNwb25zZSA9IHN1YnNldChJRk5nX3Jlc3BvbnNlLCBlbnNlbWJsX2dlbmVfaWQgJWluJSByb3duYW1lcyh1bmZpbHRlcmVkX2NvdW50cykpCnR5cGUxX2NvdW50cyA9IHVuZmlsdGVyZWRfY291bnRzW3R5cGVJX0lGTl9yZXNwb25zZSRlbnNlbWJsX2dlbmVfaWQsIG1wX2RlcyRjb3ZpZF9jb25maXJtZWQgPT0gVFJVRV0KdHlwZTFfY291bnRzID0gYXMuZGF0YS5mcmFtZShjb2xNZWFucyh0eXBlMV9jb3VudHMpKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGUiKQpjb2xuYW1lcyh0eXBlMV9jb3VudHMpWzJdID0gInR5cGVJX0lGTl9yZXNwb25zZSIKdHlwZTJfY291bnRzID0gdW5maWx0ZXJlZF9jb3VudHNbSUZOZ19yZXNwb25zZSRlbnNlbWJsX2dlbmVfaWQsIG1wX2RlcyRjb3ZpZF9jb25maXJtZWQgPT0gVFJVRV0KdHlwZTJfY291bnRzID0gYXMuZGF0YS5mcmFtZShjb2xNZWFucyh0eXBlMl9jb3VudHMpKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGUiKQpjb2xuYW1lcyh0eXBlMl9jb3VudHMpWzJdID0gIklGTmdfcmVzcG9uc2UiCmlmbl9jb3VudHMgPSB1bmZpbHRlcmVkX2NvdW50c1tpbnRlcnNlY3QoSUZOZ19yZXNwb25zZSRlbnNlbWJsX2dlbmVfaWQsIHR5cGVJX0lGTl9yZXNwb25zZSRlbnNlbWJsX2dlbmVfaWQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXBfZGVzJGNvdmlkX2NvbmZpcm1lZCA9PSBUUlVFXQppZm5fY291bnRzID0gYXMuZGF0YS5mcmFtZShjb2xNZWFucyhpZm5fY291bnRzKSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlIikKY29sbmFtZXMoaWZuX2NvdW50cylbMl0gPSAiZ2VuZXJhbF9JRk5fcmVzcG9uc2UiCgpjb3ZpZF91bWFwID0gY292aWRfdW1hcCAlPiUgCiAgZHBseXI6OnNlbGVjdCgtYyh0eXBlSV9JRk5fcmVzcG9uc2UsIElGTmdfcmVzcG9uc2UsIGdlbmVyYWxfSUZOX3Jlc3BvbnNlKSkgJT4lIAogIGxlZnRfam9pbiguLCB0eXBlMV9jb3VudHMpICU+JSAKICBsZWZ0X2pvaW4oLiwgdHlwZTJfY291bnRzKSAlPiUgCiAgbGVmdF9qb2luKC4sIGlmbl9jb3VudHMpCmBgYAogICAKIyMjIFBsb3QgICAKYGBge3J9CmdncGxvdChjb3ZpZF91bWFwLCBhZXMoeCA9IGZpbml0ZV9kYXlfb2ZfaW50dWJhdGlvbiwgeSA9IHR5cGVJX0lGTl9yZXNwb25zZSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9IGZpZzJfcGFsWzJdKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiwgZmFtaWx5ID0gIkFyaWFsIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICB5bGFiKCJBdmVyYWdlIEdPOjAwNjAzMzcgRXhwcmVzc2lvbiIpICsKICB4bGFiKCJEYXkgb2YgTWVjaGFuaWNhbCBWZW50aWxhdGlvbiIpCgpnZ3Bsb3QoY292aWRfdW1hcCwgYWVzKHggPSBmaW5pdGVfZGF5X29mX2ludHViYXRpb24sIHkgPSBJRk5nX3Jlc3BvbnNlKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gZmlnMl9wYWxbMl0pICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyLCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIHlsYWIoIkF2ZXJhZ2UgR086MDA2MDMzMyBFeHByZXNzaW9uIikgKwogIHhsYWIoIkRheSBvZiBNZWNoYW5pY2FsIFZlbnRpbGF0aW9uIikKCgpnZ3Bsb3QoY292aWRfdW1hcCwgYWVzKHggPSBmaW5pdGVfZGF5X29mX2ludHViYXRpb24sIHkgPSBnZW5lcmFsX0lGTl9yZXNwb25zZSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9IGZpZzJfcGFsWzJdKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiwgZmFtaWx5ID0gIkFyaWFsIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICB5bGFiKCJBdmVyYWdlIElGTiByZXNwb25zZSBFeHByZXNzaW9uIikgKwogIHhsYWIoIkRheSBvZiBNZWNoYW5pY2FsIFZlbnRpbGF0aW9uIikKYGBgICAgCiAgIAojIyMgQ29ycmVsYXRpb25zICAgCmBgYHtyfQpjb3IudGVzdChjb3ZpZF91bWFwJHR5cGVJX0lGTl9yZXNwb25zZSwgY292aWRfdW1hcCRmaW5pdGVfZGF5X29mX2ludHViYXRpb24pCmNvci50ZXN0KGNvdmlkX3VtYXAkSUZOZ19yZXNwb25zZSwgY292aWRfdW1hcCRmaW5pdGVfZGF5X29mX2ludHViYXRpb24pCmNvci50ZXN0KGNvdmlkX3VtYXAkZ2VuZXJhbF9JRk5fcmVzcG9uc2UsIGNvdmlkX3VtYXAkZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uKQpgYGAKCgogICAKIyBTZWNvbmQgYmF0Y2ggb2YgcGljbyBvcHRpbWl6YXRpb24gICAKTGV0J3MgZm9jdXMgb24gaW50ZXJmZXJvbi1oaSB2cyBpbnRlcmZlcm9uLWxvdyBzYW1wbGVzICAgCiMjIyBJZGVudGlmeSBpbnRlcmVzdGluZyAgIApgYGB7cn0KbGFzdF9iYXRjaCA9IGMoMzAwMzEyMzg5LCAzMDQwMTI2OTksIDMwNDAxNzU1MywgMzA0MDIwMjk4LCAzMDQwMjAzNjIsCiAgICAgICAgICAgICAgIDM0MDIyNDgwOCwgMzQwMjMzODk2LCAzNDAyMzk3ODksIDM0MDIzOTc5MCwgMzQwMjM5ODA1KQpnb29kX3NhbXBsZXMgPSBtcF9kZXNbLCAoKCFpcy5uYShtcF9kZXMkUklOKSAmIG1wX2RlcyRSSU4gPj0gNykgJiAKICAgICAgICAgICAgICAgICAgICBtcF9kZXMkU1RBUl9tcWNfZ2VuZXJhbHN0YXRzX3N0YXJfdW5pcXVlbHlfbWFwcGVkX3BlcmNlbnQgPj0gMzAgJgogICAgICAgICAgICAgICAgICAgIG1wX2RlcyRmZWF0dXJlQ291bnRzX21xY19nZW5lcmFsc3RhdHNfZmVhdHVyZWNvdW50c19wZXJjZW50X2Fzc2lnbmVkID49IDMwKSAmCiAgICAgICAgICAgICAgICAgICAgbXBfZGVzJFJOQV9jb25jZW50cmF0aW9uX3BnX3VsID49IDEyNV0KcmVtYWluaW5nX2ludGVyZXN0aW5nID0gc2V0ZGlmZihnb29kX3NhbXBsZXMkc2FtcGxlLCBsYXN0X2JhdGNoKQppbnRlcmVzdGluZ19tZXRhZGF0YSA9IHN1YnNldCh0b3RhbF91bWFwLCBzYW1wbGUgJWluJSByZW1haW5pbmdfaW50ZXJlc3RpbmcpCnRhYmxlKGludGVyZXN0aW5nX21ldGFkYXRhJHBuYV90eXBlKQpnZ3Bsb3QoaW50ZXJlc3RpbmdfbWV0YWRhdGEsIGFlcyh4ID0gcG5hX3R5cGUsIHkgPSBBRXB1cnBsZSkpICsKICBnZW9tX2JveHBsb3QoKQpzZWxlY3Rpb24gPSBpbnRlcmVzdGluZ19tZXRhZGF0YSAlPiUgCiAgZmlsdGVyKHBuYV90eXBlICE9ICJPdGhlciBQbmV1bW9uaWEiIHwgc2FtcGxlID09IDM0MDIzNTExMCkgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlLCB0dWJlX2xvY19tYWNyb3BoUk5BX2JveElELCBSTkFfY29uY2VudHJhdGlvbl9wZ191bCkgJT4lIAogIG11dGF0ZShkaWx1dGlvbiA9IGlmZWxzZSgoMjUwIC8gUk5BX2NvbmNlbnRyYXRpb25fcGdfdWwpIDwgMC40LAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSByb3VuZCgxIC8gKDI1MCAvIFJOQV9jb25jZW50cmF0aW9uX3BnX3VsKSAvIDUpICogNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gPSAxKSkgJT4lIAogIG11dGF0ZSh2b2xfZm9yXzI1MF9wZyA9IHJvdW5kKDI1MCAvIFJOQV9jb25jZW50cmF0aW9uX3BnX3VsICogZGlsdXRpb24sIGRpZ2l0cyA9IDIpKQp3cml0ZS5jc3Yoc2VsZWN0aW9uLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvMjAwNzEzX3BpY29fb3B0X2JhdGNoMi5jc3YiKQpzZWxlY3Rpb24KYGBgCiAgIAojIENvbmNsdXNpb25zICAgCiMjIE91dHB1dCBkYXRhIGZvciBwb3N0ZXJpdHkgICAKYGBge3J9CmZpbmFsX2NvdW50c19yYXcgPSBjb3VudHMobXBfZGVzLCBub3JtYWxpemVkID0gRikKCiNjbGVhbiBtZXRhZGF0YSBmb3Igc2FmZSBzaGFyaW5nCmZpbmFsX21kX3NhZmUgPSBjb2xEYXRhKG1wX2RlcykgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZHBseXI6OnNlbGVjdChzYW1wbGUsIGFnZSwgc2V4LCByYWNlID0gcmFjZXMsIGV0aG5pY2l0eSwgZGlhZ25vc2lzID0gcG5hX3R5cGUsIAogICAgICAgICAgICAgICAgZGF5X29mX3ZlbnRpbGF0aW9uID0gZmluaXRlX2RheV9vZl9pbnR1YmF0aW9uLCBzdHVkeV9pZCkKI2NvbnZlcnQgc2NyaXB0IElEcyB0byBuZXcgaWRlbnRpZmllcnMKaWRfY29udiA9IGRhdGEuZnJhbWUoc2NyaXB0X2lkID0gc2FtcGxlKHVuaXF1ZShmaW5hbF9tZF9zYWZlJHN0dWR5X2lkKSkpICU+JSAjc2h1ZmZsZSBJRHMgZmlyc3QKICBtdXRhdGUoYW5vbnltaXplZF9wYXRpZW50X2lkID0gc3ByaW50ZigiJTA0ZCIsIDE6bnJvdyhpZF9jb252KSkpCiNhZGQgYmFjayB0byBtZApmaW5hbF9tZF9zYWZlID0gbGVmdF9qb2luKGZpbmFsX21kX3NhZmUsIGlkX2NvbnYsIGJ5ID0gYygic3R1ZHlfaWQiID0gInNjcmlwdF9pZCIpKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtc3R1ZHlfaWQpCgp3cml0ZS5jc3YoZmluYWxfY291bnRzX3JhdywgIi9wcm9qZWN0cy9iMTAzOC9QdWxtb25hcnkvcmdyYW50L3NjcmlwdF9idWxrL0FuYWx5c2lzL0dFT19vdXRwdXQvMjAwNzI0X3Jhd19jb3VudHNfZ2VvLmNzdiIpCndyaXRlLmNzdihmaW5hbF9tZF9zYWZlLCAiL3Byb2plY3RzL2IxMDM4L1B1bG1vbmFyeS9yZ3JhbnQvc2NyaXB0X2J1bGsvQW5hbHlzaXMvR0VPX291dHB1dC8yMDA3MjRfZGVpZGVudGlmaWVkX21ldGFkYXRhX2dlby5jc3YiKQpgYGAKCg==